简单分析MySQL中的primary key功能

在5.1.46中优化器在对primary key的选择上做了一点改动:

Performance: While looking for the shortest index for a covering index scan, the optimizer did not consider the full row length for a clustered primary key, as in InnoDB. Secondary covering indexes will now be preferred, making full table scans less likely。

该版本中增加了find_shortest_key函数,该函数的作用可以认为是选择最小key length的

索引来满足我们的查询。

该函数是怎么工作的:

What find_shortest_key should do is the following. If the primary key is a covering index

and is clustered, like in MyISAM, then the behavior today should remain the same. If the

primary key is clustered, like in InnoDB, then it should not consider using the primary

key because then the storage engine will have to scan through much more data.

调用Primary_key_is_clustered(),当返回值为true,执行find_shortest_key:选择key length最小的覆盖索引(Secondary covering indexes),然后来满足查询。

首先在5.1.45中测试:

$mysql -V

mysql Ver 14.14 Distrib 5.1.45, for unknown-linux-gnu (x86_64) using EditLine wrapper

root@test 03:49:45>create table test(id int,name varchar(20),name2 varchar(20),d datetime,primary key(id)) engine=innodb;

Query OK, 0 rows affected (0.16 sec)

root@test 03:49:47>insert into test values(1,'xc','sds',now()),(2,'xcx','dd',now()),(3,'sdds','ddd',now()),(4,'sdsdf','dsd',now()),(5,'sdsdaa','sds',now());

Query OK, 5 rows affected (0.00 sec)

Records: 5 Duplicates: 0 Warnings: 0

root@test 03:49:51>

root@test 03:49:51>insert into test values(6,'xce','sdsd',now()),(7,'xcx','sdsd',now()),(8,'sdds','sds',now()),(9,'sdsdsdf','sdsdsd',now()),(10,'sdssdfdaa','sdsdsd',now());

Query OK, 5 rows affected (0.00 sec)

Records: 5 Duplicates: 0 Warnings: 0

创建索引ind_1:

root@test 03:49:53>alter table test add index ind_1(name,d);

Query OK, 0 rows affected (0.09 sec)

Records: 0 Duplicates: 0 Warnings: 0

root@test 03:50:08>explain select count(*) from test;

+—-+————-+——-+——-+—————+———+———+——+——+————-+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+—-+————-+——-+——-+—————+———+———+——+——+————-+

| 1 | SIMPLE | test | index | NULL | PRIMARY | 4 | NULL | 10 | Using index |

+—-+————-+——-+——-+—————+———+———+——+——+————-+

1 row in set (0.00 sec)

添加ind_2:

root@test 08:04:35>alter table test add index ind_2(d);

Query OK, 0 rows affected (0.07 sec)

Records: 0 Duplicates: 0 Warnings: 0

root@test 08:04:45>explain select count(*) from test;

+—-+————-+——-+——-+—————+———+———+——+——+————-+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+—-+————-+——-+——-+—————+———+———+——+——+————-+

| 1 | SIMPLE | test | index | NULL | PRIMARY | 4 | NULL | 10 | Using index |

+—-+————-+——-+——-+—————+———+———+——+——+————-+

1 row in set (0.00 sec)

上面的版本【5.1.45】中,可以看到优化器选择使用主键来完成扫描,并没有使用ind_1,ind_2来完成查询;

接下来是:5.1.48

$mysql -V

mysql Ver 14.14 Distrib 5.1.48, for unknown-linux-gnu (x86_64) using EditLine wrapper

root@test 03:13:15> create table test(id int,name varchar(20),name2 varchar(20),d datetime,primary key(id)) engine=innodb;

Query OK, 0 rows affected (0.00 sec)

root@test 03:48:04>insert into test values(1,'xc','sds',now()),(2,'xcx','dd',now()),(3,'sdds','ddd',now()),(4,'sdsdf','dsd',now()),(5,'sdsdaa','sds',now());

Query OK, 5 rows affected (0.00 sec)

Records: 5 Duplicates: 0 Warnings: 0

root@test 03:48:05>insert into test values(6,'xce','sdsd',now()),(7,'xcx','sdsd',now()),(8,'sdds','sds',now()),(9,'sdsdsdf','sdsdsd',now()),(10,'sdssdfdaa','sdsdsd',now());

Query OK, 5 rows affected (0.01 sec)

Records: 5 Duplicates: 0 Warnings: 0

创建索引ind_1:

root@test 03:13:57>alter table test add index ind_1(name,d);

Query OK, 0 rows affected (0.01 sec)

Records: 0 Duplicates: 0 Warnings: 0

root@test 03:15:55>explain select count(*) from test;

+—-+————-+——-+——-+—————+——-+———+——+——+————-+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+—-+————-+——-+——-+—————+——-+———+——+——+————-+

| 1 | SIMPLE | test | index | NULL | ind_1 | 52 | NULL | 10 | Using index |

+—-+————-+——-+——-+—————+——-+———+——+——+————-+

root@test 08:01:56>alter table test add index ind_2(d);

Query OK, 0 rows affected (0.03 sec)

Records: 0 Duplicates: 0 Warnings: 0

添加ind_2:

root@test 08:02:09>explain select count(*) from test;

+—-+————-+——-+——-+—————+——-+———+——+——+————-+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+—-+————-+——-+——-+—————+——-+———+——+——+————-+

| 1 | SIMPLE | test | index | NULL | ind_2 | 9 | NULL | 10 | Using index |

+—-+————-+——-+——-+—————+——-+———+——+——+————-+

1 row in set (0.00 sec)

版本【5.1.48】中首先明智的选择ind_1来完成扫描,并没有考虑到使用主键(全索引扫描)来完成查询,随后添加ind_2,由于 ind_1的key长度是大于ind_2 key长度,所以mysql选择更优的ind_2来完成查询,可以看到mysql在选择方式上也在慢慢智能了。

观察性能:

5.1.48

root@test 08:49:32>set profiling =1;

Query OK, 0 rows affected (0.00 sec)

root@test 08:49:41>select count(*) from test;

+———-+

| count(*) |

+———-+

| 5242880 |

+———-+

1 row in set (1.18 sec)

root@test 08:56:30>show profile cpu,block io for query 1;

+——————————–+———-+———-+————+————–+—————+

| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |

+——————————–+———-+———-+————+————–+—————+

| starting | 0.000035 | 0.000000 | 0.000000 | 0 | 0 |

| checking query cache for query | 0.000051 | 0.000000 | 0.000000 | 0 | 0 |

| Opening tables | 0.000014 | 0.000000 | 0.000000 | 0 | 0 |

| System lock | 0.000005 | 0.000000 | 0.000000 | 0 | 0 |

| Table lock | 0.000010 | 0.000000 | 0.000000 | 0 | 0 |

| init | 0.000015 | 0.000000 | 0.000000 | 0 | 0 |

| optimizing | 0.000007 | 0.000000 | 0.000000 | 0 | 0 |

| statistics | 0.000015 | 0.000000 | 0.000000 | 0 | 0 |

| preparing | 0.000012 | 0.000000 | 0.000000 | 0 | 0 |

| executing | 0.000007 | 0.000000 | 0.000000 | 0 | 0 |

| Sending data | 1.178452 | 1.177821 | 0.000000 | 0 | 0 |

| end | 0.000016 | 0.000000 | 0.000000 | 0 | 0 |

| query end | 0.000005 | 0.000000 | 0.000000 | 0 | 0 |

| freeing items | 0.000040 | 0.000000 | 0.000000 | 0 | 0 |

| logging slow query | 0.000002 | 0.000000 | 0.000000 | 0 | 0 |

| logging slow query | 0.000086 | 0.000000 | 0.000000 | 0 | 0 |

| cleaning up | 0.000006 | 0.000000 | 0.000000 | 0 | 0 |

+——————————–+———-+———-+————+————–+—————+

对比性能:

5.1.45

root@test 08:57:18>set profiling =1;

Query OK, 0 rows affected (0.00 sec)

root@test 08:57:21>select count(*) from test;

+———-+

| count(*) |

+———-+

| 5242880 |

+———-+

1 row in set (1.30 sec)

root@test 08:57:27>show profile cpu,block io for query 1;

+——————————–+———-+———-+————+————–+—————+

| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |

+——————————–+———-+———-+————+————–+—————+

| starting | 0.000026 | 0.000000 | 0.000000 | 0 | 0 |

| checking query cache for query | 0.000041 | 0.000000 | 0.000000 | 0 | 0 |

| Opening tables | 0.000014 | 0.000000 | 0.000000 | 0 | 0 |

| System lock | 0.000005 | 0.000000 | 0.000000 | 0 | 0 |

| Table lock | 0.000008 | 0.000000 | 0.000000 | 0 | 0 |

| init | 0.000015 | 0.000000 | 0.000000 | 0 | 0 |

| optimizing | 0.000006 | 0.000000 | 0.000000 | 0 | 0 |

| statistics | 0.000014 | 0.000000 | 0.000000 | 0 | 0 |

| preparing | 0.000012 | 0.000000 | 0.000000 | 0 | 0 |

| executing | 0.000007 | 0.000000 | 0.000000 | 0 | 0 |

| Sending data | 1.294178 | 1.293803 | 0.000000 | 0 | 0 |

| end | 0.000016 | 0.000000 | 0.000000 | 0 | 0 |

| query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |

| freeing items | 0.000040 | 0.000000 | 0.001000 | 0 | 0 |

| logging slow query | 0.000002 | 0.000000 | 0.000000 | 0 | 0 |

| logging slow query | 0.000080 | 0.000000 | 0.000000 | 0 | 0 |

| cleaning up | 0.000006 | 0.000000 | 0.000000 | 0 | 0 |

+——————————–+———-+———-+————+————–+—————+

从上面的profile中可以看到在Sending data上,差异还是比较明显的,mysql不需要扫描整个表的页块,而是扫描表中索引key最短的索引页块来完成查询,这样就减少了很多不必要的数据。

PS:innodb是事务引擎,所以在叶子节点中除了存储本行记录外,还会多记录一些关于事务的信息(DB_TRX_ID ,DB_ROLL_PTR 等),因此单行长度额外开销20个字节左右,最直观的方法是将myisam转为innodb,存储空间会明显上升。那么在主表为t(id,name,pk(id)),二级索引ind_name(name,id),这个时候很容易混淆,即使只有两个字段,第一索引还是比第二索引要大(可以通过innodb_table_monitor观察表的的内部结构)在查询所有id的时候,优化器还是会选择第二索引ind_name。相关阅读:

mysql优化连接数防止访问量过高的方法

jQuery中使用data()方法读取HTML5自定义属性data-*实例

Win10新版本中Insider Hub会员应用消失不见了怎么添加

Android 实现微信登录详解

Mysql的游标的定义使用及关闭深入分析

MySQL函数讲解(MySQL函数大全)

使用CSS+JavaScript或纯js实现半透明遮罩效果的实例分享

Linux系统如何安装mongodb数据库Mongo扩展

Win8.1系统打开应用商店提示错误代码0x80080005的解决方法

Win8系统怎么把固定在开始屏幕上的图标重命名?

MAC怎么设置默认浏览器有哪些方法

C#根据年月日计算星期几的函数

C#动态生成按钮及定义按钮事件的方法

centos中netspeeder网络加速/优化器的安装方法

php mysql primary key_MySQL_简单分析MySQL中的primary key功能,在5.1.46中优化器在对primary key - phpStudy...相关推荐

  1. php mysql primary key_简单分析MySQL中的primary key功能_MySQL

    在5.1.46中优化器在对primary key的选择上做了一点改动: Performance: While looking for the shortest index for a covering ...

  2. 如何在App中实现朋友圈功能之四在朋友圈中添加发送图片功能——箭扣科技Arrownock

    如何在App中实现朋友圈功能 之四 在朋友圈中添加发送图片功能 实现概念: 当用户在界面点击发送按钮的时候,如果已经有选择好的图片,我们的做法是先上传图片到服务器,再将图片Id作为Post的属性上传. ...

  3. mysql数据库用户简单分析_如何用SQLyog来分析MySQL数据库详解

    用SQLyog来分析MySQL数据库: SOLyog的下载.安装以及使用很简单.我去了相关网站下载,它只有384K字节大小.它把两个文件(一个可执行文件.exe和一个动态链接库文件.dll)安装到C: ...

  4. mysql distinct 慢_分析MySQL中优化distinct的技巧

    有这样的一个需求:select count(distinct nick) from user_access_xx_xx; 这条sql用于统计用户访问的uv,由于单表的数据量在10G以上,即使在user ...

  5. mysql解析运行时间_分析 MySQL 语句运行时间

    为了验证select 1 与 select 1 from tableName 与 select * from tableName的执行效率,需要测试一下各自执行的时间.于是总结一下,查看mysql语句 ...

  6. 微信扫码 android sdk,H5中js-sdk扫码功能,Android手机微信中无法调用扫码?

    我的H5对接微信JS-SDK中的扫码功能,发现在Android手机微信中无法调用扫码功能,在苹果手机微信中可以使用. 报如下错误: errMsg:scanQRCode:permissi on deni ...

  7. 简单分析MySQL 一则慢日志监控误报问题

    这篇文章主要介绍了MySQL 一则慢日志监控误报的问题分析与解决,帮助大家更好的理解和使用MySQL,感兴趣的朋友可以了解下 之前因为各种原因,有些报警没有引起重视,最近放假马上排除了一些潜在的人为原 ...

  8. mysql int()_简单谈谈MySQL中的int(m)

    我们在设计表的时候,如果碰到需要设置int(整型)的时候,通常会按照惯例(大家都这样写)设置成int(11).那么这里为什么是11呢?代表的又是什么呢? 以前我一直以为这里是在限制int显示的宽度,后 ...

  9. MySQL DEBUG_SYNC 的简单分析与测试

    http://hedengcheng.com/?p=238 转载于:https://www.cnblogs.com/zengkefu/p/5526474.html

  10. 简单mysql 查询_简单的mysql查询

    mysql是基于客户机-服务器的数据库.客户机-服务器应用分为两个不同的部分.服务器部分是负责所有数据访问和处理的一个软件. 连接mysql 要连接mysql需要知道如下 主机名: 本地为localh ...

最新文章

  1. 【GDB】gdbserver的使用,远程调试开发板
  2. 如何使用idea REST Clinet 代替PostMan发送Http请求
  3. 浅谈Java解决鸡兔同笼问题的思路
  4. 读书笔记2014年第1本:《赤裸裸的统计学》
  5. Redis启动报错:[27960] 19 Mar 13:52:32.642 # Creating Server TCP listening socket 127.0.0.1:6379: bind: N
  6. pcie组raid linux,PCIe 4.0有多强大?组RAID 0阵列之后惊呆了
  7. 【升职加薪必备架构图】Springboot学习路线汇总
  8. Solr 4.10.3 集成 IK Analyzer 2012FF 中文分词器
  9. Mujoco平面双足机器人模拟
  10. 回溯算法 --- 例题6.最大团问题
  11. openbsd_仔细看一下OpenBSD
  12. 利用Windows内置工具winsat测试硬盘速度(SSD机械盘对比)
  13. 关于“C2248 QString::QString 无法访问private成员的问题”
  14. 看完一本青春小说后的感悟。
  15. e3d教程做logo教程_AE-炫酷LED灯动画 LOGO片头制作(E3D插件)
  16. 三大框架整合步骤(详细)
  17. 前端算法学习入门笔记 - JavaScript
  18. uniapp 即时通讯_uni-App 仿微信 App 即时通讯|vue+uniapp 聊天
  19. 素描学习入门零基础学习静物素描的几种方法
  20. 使用jmeter进行http压力测试(适合小白观看)

热门文章

  1. 路由器显示DNS服务器设置错误,路由器dns设置错误怎么处理
  2. 2D人体姿态估计 - Stakced Hourglass Network(SHN)个人理解
  3. 基于Python绘制一个摸鱼倒计时界面
  4. Windows 10搭建SVN服务器
  5. Jenkins插件源使用国内镜像中心的最新方法
  6. (转载)傅里叶分析之掐死教程(完整版)
  7. 牛客网暑期ACM多校训练营(第三场) J.Distance to Work 计算几何
  8. java tiff 压缩,使用Java ImageIO进行Tiff压缩
  9. android studio 讯飞语音,讯飞语音 使用步骤(针对androidStudio):语音转文字:(示例代码)...
  10. android免费离线讯飞语音合成