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,一经查实,立即删除!

相关文章

Centos7常用命令[挂载文件系统]

Centos7常用命令[挂载文件系统]------------------------------------------------------------------------------# 挂载一个叫做hda2的盘-确定目录/mnt/hda2已经存在[rootlocalhost ~]# mount /dev/hda2 /mnt/hda2# 卸载一个叫做hda2的盘-先从挂载点/mnt/hda2退出[rootlocalh…

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…

Tensorflow Python API 翻译(sparse_ops)

作者:chen_h 微信号 & QQ:862251340 微信公众号:coderpai 我的博客:请点击这里计划现将 tensorflow 中的 Python API 做一个学习,这样方便以后的学习。 原文链接该章介绍有关稀疏张量的API稀疏张量表示对于多维稀疏…

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

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

ORA-01861: 文字与格式字符串不匹配

select to_date(20160401000000,yyyy-mm-dd) from dual; ---------- 报错:ORA-01861: 文字与格式字符串不匹配 原因:字符串20160401000000与要转换的格式 yyyy-mm-dd 格式不对。 20160401000000 是 yyyymmddhh24miss 格式的 -------- select to_da…

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

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

java socket建立长连接_Java Web项目中使用Socket通信多线程、长连接的方法

很多时候在javaweb项目中我们需要用到Socket通信来实现功能,在web中使用Socket我们需要建立一个监听程序,在程序启动时,启动socket监听。我们的应用场景是在java项目中,需要外接如一个硬件设备,通过tcp通信&#xff0c…

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…

hadoop eclipse plugin windows下载集合

收集了hadoop稳定版本的eclipse plugin for windows。资源分一律为0分 hadoop-eclipse-plugin-1.2.1.jar http://download.csdn.net/detail/zengmingen/9488180 hadoop-eclipse-plugin-2.2.0.jar http://download.csdn.net/detail/zengmingen/9488182 hadoop-eclipse-pl…

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

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

104. Maximum Depth of Binary Tree

104. Maximum Depth of Binary Tree 题目 Given a binary tree, find its maximum depth.The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 解析 // Maximum Depth of Binary Tree class Solution { publ…

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; …

java 远程调用url_使用Java的URL/HttpURLConnection进行远程调用(POST请求)

利用Java的HttpURLConnection进行远程url请求(调用远程接口)测试类:请求类型为json,以post方式请求,利用OutputStream写入数据实体类:public class User implementsSerializable {privateString name;privateString password;publicString ge…

LindDotNetCore~职责链模式的应用

回到目录 职责链模式 它是一种设计模块,主要将操作流程与具体操作解耦,让每个操作都可以设置自己的操作流程,这对于工作流应用是一个不错的选择! 下面是官方标准的定义:责任链模式是一种设计模式。在责任链模式里&…

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…

构件之法读书笔记04

我们前两周我们团队一起制作了一个大学生记账软件,但是我们没有对我们的软件进行测试,只要是这个功能能够顺利进行,我们就觉得OK。 其实,我认为我们的软件是有问题的,对于一些极限的操作能否完成,在各种环境…

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

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

【Spark】开发Spark选择Java还是Scala?

Spark-Java-Scala-哪种语言 spark java 支持_百度搜索(1 封私信)Spark 中用 Scala 和 java 开发有什么区别? - 知乎(1 封私信)Spark平台下,scala比java更有优势么? - 知乎

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也不需要类的继承关系,只要类的数据就够…