mysql主键 命中率_mysql主键问题

MySQL主键

一. MySQL主键设计原则

MySQL主键应当是对用户没有意义的。

MySQL主键应该是单列的,以便提高连接和筛选操作的效率(当然复合主键是可以的,只是不建议)

永远也不要更新MySQL主键

MySQL主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等

MySQL主键应当有计算机自动生成。

二. 主键添加方法

在创建表的时候,直接在字段之后,添加primary key关键字

create table my_pri1(

name varchar(20) not null comment ‘姓名‘,

number char(10) primary key comment ‘学号‘

)charset utf8;

在创建表的时候,在所有的字段之后,使用primary key(主键字段列表)来创建主键,此处可用来添加复合主键(不建议)。

create table my_pri2(

number char(10) not null comment ‘学号‘,

course char(10) not null comment ‘课程编号‘,

score tinyint unsigned default 60,

-- 增加主键限制,学号和课程编号应该是对应的,具有唯一性

primary key(number) //primary key(number,course)

)charset utf8;

当表创建完之后,额外追加主键,可以直接追加主键,也可以通过修改表字段的属性追加主键

alter table my_pri3 modify course char(10) primary key comment ‘课程编号‘; -- 不建议使用

alter table my_pri3 add primary key(course); -- 推荐使用

三. 主键设计的常用方案

1. 自增ID

优点:

1) 数据库自动编号,速度快,而且是增量增长,聚集型主键按顺序存放,对于检索非常有利。

2) 数字型,占用空间小,易排序,在程序中传递方便。

缺点:

1) 不支持水平分片架构,水平分片的设计当中,这种方法显然不能保证全局唯一。

2) 表锁,在MySQL5.1.22之前,InnoDB自增值是通过其本身的自增长计数器来获取值,该实现方式是通过表锁机制来完成的(AUTO-INC LOCKING)。锁不是在每次事务完成后释放,而是在完成对自增长值插入的SQL语句后释放,要等待其释放才能进行后续操作。比如说当表里有一个auto_increment字段的时候,innoDB会在内存里保存一个计数器用来记录auto_increment的值,当插入一个新行数据时,就会用一个表锁来锁住这个计数器,直到插入结束。如果大量的并发插入,表锁会引起SQL堵塞。在5.1.22之后,InnoDB为了解决自增主键锁表的问题,引入了参数innodb_autoinc_lock_mode:

0:通过表锁的方式进行,也就是所有类型的insert都用AUTO-inc locking(表锁机制)。

1:默认值,对于simple insert 自增长值的产生使用互斥量对内存中的计数器进行累加操作,对于bulk insert 则还是使用表锁的方式进行。

2:对所有的insert-like 自增长值的产生使用互斥量机制完成,性能最高,并发插入可能导致自增值不连续,可能会导致Statement 的 Replication 出现不一致,使用该模式,需要用 Row Replication的模式。

3) 自增主键不连续,对表增加属性AUTO_INCREMENT=16时,主键就会从16开始自增起;实际的插入数据操作中,可能存在不连续的主键值。

2. UUID

优点:

1) 全局唯一性、安全性、可移植性。

2) 能够保证独立性,程序可以在不同的数据库间迁移,效果不受影响。

3) 保证生成的ID不仅是表独立的,而且是库独立的,在你切分数据库的时候尤为重要

缺点:

1) 针对InnoDB引擎会徒增IO压力,InnoDB为聚集主键类型的引擎,数据会按照主键进行排序,由于UUID的无序性,InnoDB会产生巨大的IO压力。InnoDB主键索引和数据存储位置相关(簇类索引),uuid 主键可能会引起数据位置频繁变动,严重影响性能。

2) UUID长度过长,一个UUID占用128个比特(16个字节)。主键索引KeyLength长度过大,而影响能够基于内存的索引记录数量,进而影响基于内存的索引命中率,而基于硬盘进行索引查询性能很差。严重影响数据库服务器整体的性能表现。

3.自定义序列

自定义序列列表:就是在库中建一张用于生成序列的表来存储序列信息,序列生成的策略通过程序层面来实现。如下所示,构建一张序列表:

CREATE TABLE `sequence` (

`name` varchar(50) NOT NULL,

`id` bigint(20) unsigned NOT NULL DEFAULT ‘0‘,

PRIMARY KEY (`name`)

) ENGINE=InnoDB;

注意区别,id字段不是自增的,也不是主键。在使用前,我们需要先插入一些初始化数据:

INSERT INTO `sequence` (`name`) VALUES

(‘users‘), (‘photos‘), (‘albums‘), (‘comments‘);

接下来,我们可以通过执行下面的SQL语句来获得新的照片ID:

UPDATE `sequence` SET `id` = LAST_INSERT_ID(`id` + 1) WHERE `name` = ‘photos‘;

SELECT LAST_INSERT_ID();

我们执行了一个更新操作,将id字段增加1,并将增加后的值传递到LAST_INSERT_ID函数, 从而指定了LAST_INSERT_ID的返回值。

实际上,我们不一定需要预先指定序列的名字。如果我们现在需要一种新的序列,我们可以直接执行下面的SQL语句:

INSERT INTO `sequence` (`name`) VALUES(‘new_business‘) ON DUPLICATE KEY UPDATE `id` = LAST_INSERT_ID(`id` + 1);

SELECT LAST_INSERT_ID();

这种方案的问题在于序列生成的逻辑脱离了数据库层,由应用层负责,增加了开发复杂度。不过一般序列值都是通过Java的框架去自动生成的,具体就不在MySQL系列文章阐述。

四. 如何解决水平分片的需求

UUID

由于UUID出现重复的概率基本可以忽略,所以对分片是天生支持的。

独立的序列库

单独建立一个库用来生成ID,在Shard中的每张表在这个ID库中都有一个对应的表,而这个对应的表只有一个字段, 这个字段是自增的。当我们需要插入新的数据,我们首先在ID库中的相应表中插入一条记录,以此得到一个新的ID, 然后将这个ID作为插入到Shard中的数据的主键。这个方法的缺点就是需要额外的插入操作,如果ID库变的很大, 性能也会随之降低。所以一定要保证ID库的数据集不要太大,一个办法是定期清理前面的记录。

复合标识符

这种做法是通过联合主键的策略,即通过两个字段来生成一个唯一标识,前半部分是分片标识符,后半部分是本地生成的标识符(比如使用AUTO_INCREMENT生成)。

带分库策略的自定义序列表

这种做法可以基于上面提到的自定义序列表的方法的基础上,做一些技巧性的调整。即如下:

UPDATE `sequence` SET `id` = LAST_INSERT_ID(`id` + 1) WHERE `name` = ‘photos‘;

SELECT LAST_INSERT_ID();

这里的id初始值设定上要求不同的分片取不同的值,且必须连续。同时将每次递增的步长设定为服务器数目。

比如有3台机器,那么我们只要将初始值分别设置为1,2,3. 然后执行下面的语句即可:

UPDATE `sequence` SET `id` = LAST_INSERT_ID(`id` + 3) WHERE `name` = ‘photos‘;

SELECT LAST_INSERT_ID();

这就可以解决主键生成冲突的问题。但是如果在运行一段时间后要进行动态扩充分片数的时候,需要对序列初始值做一次调整,以确保其连续性,否则依然可能存在冲突的可能。当然这些逻辑可以封装在数据访问层的代码中。

五. 主键的必要性

表中每一行都应该有可以唯一标识自己的一列(或一组列)。虽然并不总是都需要主键,但大多数数据库设计人员都应保证他们创建的每个表有一个主键,以便于以后数据操纵和管理。其实即使你不建主键,MySQL(InnoDB引擎)也会自己建立一个隐藏6字节的ROWID作为主键列,详细可以参见[这里]

因为,InnoDB引擎使用聚集索引,数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL 会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)

8317c23c602d2c3a08d38c5ba8bf7b03.png

所以在使用innoDB表时要避免随机的(不连续且值的分布范围非常大)聚簇索引,特别是针对I/O密集型的应用。例如:从性能角度考虑,使用UUID的方案就会导致聚簇索引的插入变得完全随机。

主键的数据类型选择

关于主键的类型选择上最常见的争论是用整型还是字符型的问题,关于这个问题《高性能MySQL》一书中有明确论断:

整数通常是标识列的最好选择,因为它很快且可以使用AUTO_INCREAMENT,如果可能,应该避免使用字符串类型作为标识列,因为很消耗空间,且通常比数字类型慢。

如果是使用MyISAM,则就更不能用字符型,因为MyISAM默认会对字符型采用压缩引擎,从而导致查询变得非常慢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/539667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hadoop SecondNamenode

一、定义 * The Secondary Namenode is a helper to the primary Namenode. * The Secondary is responsible for supporting periodic checkpoints * of the HDFS metadata. The current design allows only one Secondary * Namenode per HDFs cluster. * The Secondary Nam…

高性能mysql 小查询_高性能MySql进化论(十一):常见查询语句的优化

总结一下常见查询语句的优化方式1 COUNT1. COUNT的作用 COUNT(table.filed)统计的该字段非空值的记录行数 COUNT(*)或者是COUNT(not nullable field) 统计的是全表的行数如果要是统计全表记录数,COUNT(*)效率会比COUNT(not nullable fie…

首席架构师徐海峰眼中的架构和出色的架构师

CSDN架构领域编辑采访了一些与会讲师,谈谈他们将在会上分享的内容、相关技术和程序人生,带你领略讲师风采。 本期我们采访的讲师是来自阅文集团首席架构师徐海峰,主要负责内容中心的网站架构和分布式存储、分布式计算工作。10年互联网开发经验…

hadoop-eclipse-plugin使用

下载hadoop安装包:http://www.carfab.com/apachesoftware/hadoop/common/hadoop-1.0.2/ 但是没有plugin,我到这个地方下载的:http://ishare.iask.sina.com.cn/f/23642243.html?fromlikecopy到你的eclipse_home的plugins下面。配置map/reduce…

java 记事本界面_JAVA/GUI程序之记事本

自上半年JAVA课程结束后,再也没有看过JAVA了,最近不是很忙,又简单的看了看,本博客纯属记录学习过程,请大神们别笑,其中错误是难免的,毕竟是新手写的博客。下面就进入我们的正题吧,复…

mapper-reducer word count 实例

统计一个文件里各单词的个数,假设这个文件很大。 原理如下图: 编写代码: WCMapper.java package zengmg.hadoop.mr.wordcount;import java.io.IOException;import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; …

MR程序的几种提交运行模式

MR程序的几种提交运行模式 本地模型运行 1/在windows的eclipse里面直接运行main方法,就会将job提交给本地执行器localjobrunner执行 ----配置path:D:\hadoop-2.7.2\bin ----配置hadoop_home:D:\hadoop-2.7.2 ----复制 hadoop.dll和winutil…

零点起飞学java视频_零点起飞学java (刘升华) 高清PDF_IT教程网

资源名称:零点起飞学java (刘升华) 高清PDF第1篇 java开发基础第1章 java概述( 教学视频:37分钟) 2第2章 基本数据类型及运算( 教学视频:52分钟) 14第3章 java程序流程控制( 教学视频:33分钟) 36第4章 类与对…

vector 修改 java_java对vector动态数组中的对象排序,以下代码有何问题,如何修改?...

展开全部package com.tx.collection;import java.util.Comparator;import java.util.Iterator;import java.util.Map;import java.util.Set;import java.util.TreeMap;import java.util.TreeSet;import java.util.Vector;public class Student {String name;int score;public S…

hadoop的序列化与java的序列化区别

java的序列化机制 java序列化时会把具体类的数据和类的继承结构信息都序列化传递。如下图hadoop的序列化机制 序列化类的数据,但是不序列化类的继承结构信息。 网络传递的时候就少了很多流量,hadoop也不需要类的继承关系,只要类的数据就够…

ORA-08103: object no longer exists

今天工具箱报错: ORA-08103: object no longer exists 查了原因,是有session在操作表,比如插入,更新等。而工具箱这个操作刚好在select表,所以报错。-------下文是英文解释----- ORA-08103: object no longer exists错…

DAY3-“忙里偷闲”找你玩耍2018-1-11

接触Java第三天,嘿嘿,今天近代史期末考试,提前一小时交卷,回宿舍继续学习,中午去见女神姐姐了,每次见完女神姐姐都是满满地动力。这次女神姐姐告诉我们要好好规划自己的时间,早上花20分钟规划好…

基于ssm出租车管理系统的设计与实现论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本出租车管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&…

Spring Security源码分析四:Spring Social实现微信社交登录

2019独角兽企业重金招聘Python工程师标准>>> 社交登录又称作社会化登录(Social Login),是指网站的用户可以使用腾讯QQ、人人网、开心网、新浪微博、搜狐微博、腾讯微博、淘宝、豆瓣、MSN、Google等社会化媒体账号登录该网站。 前言…

求方程的解 Solve the Equation

为什么80%的码农都做不了架构师?>>> 问题: Solve a given equation and return the value of x in the form of string "x#value". The equation contains only , - operation, the variable x and its coefficient. If there is …

java流读取字符串_javaIO之字符流是怎么读取的?

最近在看io相关的知识,遇到一些小问题,以下有例子来说明问题:比如:12345 是一个十进制数根据ASCII码找到是 :二进制 00110001 00110010 00110011 00110100 00110101十进制4950515253十六进制 0x310x320x330x340x35文件…

js学习

为什么80%的码农都做不了架构师?>>> /* my code */ var gArrSpell [ 1111, 2222, 3333, 4444, 5555, 6666, 7777, 8888, 999999, AAAA, bbbb, cccc, dddd, eeee, fffff ];var gArrSplDmg [11,12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24…

代码在eclipse下不报错,在doc命令行下报错--jar file和runable jar file

今天开发一个小工具,引用了Log4j,来记录日志,在eclipse下运行,代码正常,打包成jar放到doc命令行下运行报错: Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/logging/…

小马激活软件下载,当心伪小马,有病毒

官方的小马激活软件已经停止更新了,下文是官方停更公告。 http://www.pccppc.com/xiaomajihuo-html 所以小马oem7以后的都不是官方的,包含病毒。重装系统后,一般是先激活系统,再安装杀毒软件,这就给“伪小马激活工具”…

三张图搞懂JavaScript的原型对象与原型链

对于新人来说,JavaScript的原型是一个很让人头疼的事情,一来prototype容易与__proto__混淆,二来它们之间的各种指向实在有些复杂,其实市面上已经有非常多的文章在尝试说清楚,有一张所谓很经典的图,上面画了…