侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

简单分析MySQL中的primary key功能

数据库  /  管理员 发布于 6年前   240

在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 -Vmysql Ver 14.14 Distrib 5.1.45, for unknown-linux-gnu (x86_64) using EditLine wrapperroot@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: 0root@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: 0root@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: 0root@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 -Vmysql Ver 14.14 Distrib 5.1.48, for unknown-linux-gnu (x86_64) using EditLine wrapperroot@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: 0root@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: 0root@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.48root@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;+――――――――――C+―――-+―――-+――――+――――C+―――――+| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |+――――――――――C+―――-+―――-+――――+――――C+―――――+| 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 |+――――――――――C+―――-+―――-+――――+――――C+―――――+

对比性能:

5.1.45root@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;+――――――――――C+―――-+―――-+――――+――――C+―――――+| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |+――――――――――C+―――-+―――-+――――+――――C+―――――+| 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 |+――――――――――C+―――-+―――-+――――+――――C+―――――+

从上面的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的一种简单分页优化方法
    下一条:
    通过实例认识MySQL中前缀索引的用法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 分库分表的目的、优缺点及具体实现方式介绍(0个评论)
    • DevDB - 在 VS 代码中直接访问数据库(0个评论)
    • 在ubuntu系统中实现mysql数据存储目录迁移流程步骤(0个评论)
    • 在mysql中使用存储过程批量新增测试数据流程步骤(0个评论)
    • php+mysql数据库批量根据条件快速更新、连表更新sql实现(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-06
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-01
    • 2018-05
    • 2018-10
    • 2018-11
    • 2020-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2021-02
    • 2021-04
    • 2021-07
    • 2021-08
    • 2021-11
    • 2021-12
    • 2022-02
    • 2022-03
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客