国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > MySQL > 正文

簡單分析MySQL中的primary key功能

2024-07-24 13:07:09
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了MySQL中的primary key功能,包括講到了其對InnoDB使用的影響,需要的朋友可以參考下

在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的

索引來滿足我們的查詢。

該函數是怎么工作的:

 

  1. What find_shortest_key should do is the following. If the primary key is a covering index 
  2.  
  3. and is clustered, like in MyISAM, then the behavior today should remain the same. If the 
  4.  
  5. primary key is clustered, like in InnoDB, then it should not consider using the primary 
  6.  
  7. 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中測試:

 

 
  1. $mysql -V 
  2.  
  3. mysql Ver 14.14 Distrib 5.1.45, for unknown-linux-gnu (x86_64) using EditLine wrapper 
  4.  
  5. root@test 03:49:45>create table test(id int,name varchar(20),name2 varchar(20),d datetime,primary key(id)) engine=innodb; 
  6.  
  7. Query OK, 0 rows affected (0.16 sec) 
  8.  
  9. 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()); 
  10.  
  11. Query OK, 5 rows affected (0.00 sec) 
  12.  
  13. Records: 5 Duplicates: 0 Warnings: 0 
  14.  
  15. root@test 03:49:51> 
  16.  
  17. 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()); 
  18.  
  19. Query OK, 5 rows affected (0.00 sec) 
  20.  
  21. Records: 5 Duplicates: 0 Warnings: 0 

創建索引ind_1:

 

 
  1. root@test 03:49:53>alter table test add index ind_1(name,d); 
  2.  
  3. Query OK, 0 rows affected (0.09 sec) 
  4.  
  5. Records: 0 Duplicates: 0 Warnings: 0 
  6.  
  7. root@test 03:50:08>explain select count(*) from test; 
  8.  
  9. +—-+————-+——-+——-+—————+———+———+——+——+————-+ 
  10.  
  11. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
  12.  
  13. +—-+————-+——-+——-+—————+———+———+——+——+————-+ 
  14.  
  15. | 1 | SIMPLE | test | index | NULL | PRIMARY | 4 | NULL | 10 | Using index | 
  16.  
  17. +—-+————-+——-+——-+—————+———+———+——+——+————-+ 
  18.  
  19. 1 row in set (0.00 sec) 

添加ind_2:

 

 
  1. root@test 08:04:35>alter table test add index ind_2(d); 
  2.  
  3. Query OK, 0 rows affected (0.07 sec) 
  4.  
  5. Records: 0 Duplicates: 0 Warnings: 0 
  6.  
  7. root@test 08:04:45>explain select count(*) from test; 
  8.  
  9. +—-+————-+——-+——-+—————+———+———+——+——+————-+ 
  10.  
  11. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
  12.  
  13. +—-+————-+——-+——-+—————+———+———+——+——+————-+ 
  14.  
  15. | 1 | SIMPLE | test | index | NULL | PRIMARY | 4 | NULL | 10 | Using index | 
  16.  
  17. +—-+————-+——-+——-+—————+———+———+——+——+————-+ 
  18.  
  19. 1 row in set (0.00 sec) 

上面的版本【5.1.45】中,可以看到優化器選擇使用主鍵來完成掃描,并沒有使用ind_1,ind_2來完成查詢;

接下來是:5.1.48

 

 
  1. $mysql -V 
  2.  
  3. mysql Ver 14.14 Distrib 5.1.48, for unknown-linux-gnu (x86_64) using EditLine wrapper 
  4.  
  5. root@test 03:13:15> create table test(id int,name varchar(20),name2 varchar(20),d datetime,primary key(id)) engine=innodb; 
  6.  
  7. Query OK, 0 rows affected (0.00 sec) 
  8.  
  9. 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()); 
  10.  
  11. Query OK, 5 rows affected (0.00 sec) 
  12.  
  13. Records: 5 Duplicates: 0 Warnings: 0 
  14.  
  15. 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()); 
  16.  
  17. Query OK, 5 rows affected (0.01 sec) 
  18.  
  19. Records: 5 Duplicates: 0 Warnings: 0 

創建索引ind_1:

 

 
  1. root@test 03:13:57>alter table test add index ind_1(name,d); 
  2.  
  3. Query OK, 0 rows affected (0.01 sec) 
  4.  
  5. Records: 0 Duplicates: 0 Warnings: 0 
  6.  
  7. root@test 03:15:55>explain select count(*) from test; 
  8.  
  9. +—-+————-+——-+——-+—————+——-+———+——+——+————-+ 
  10.  
  11. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
  12.  
  13. +—-+————-+——-+——-+—————+——-+———+——+——+————-+ 
  14.  
  15. | 1 | SIMPLE | test | index | NULL | ind_1 | 52 | NULL | 10 | Using index | 
  16.  
  17. +—-+————-+——-+——-+—————+——-+———+——+——+————-+ 
  18.  
  19. root@test 08:01:56>alter table test add index ind_2(d); 
  20.  
  21. Query OK, 0 rows affected (0.03 sec) 
  22.  
  23. Records: 0 Duplicates: 0 Warnings: 0 
  24.  
  25. 添加ind_2: 
  26.  
  27. root@test 08:02:09>explain select count(*) from test; 
  28.  
  29. +—-+————-+——-+——-+—————+——-+———+——+——+————-+ 
  30.  
  31. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
  32.  
  33. +—-+————-+——-+——-+—————+——-+———+——+——+————-+ 
  34.  
  35. | 1 | SIMPLE | test | index | NULL | ind_2 | 9 | NULL | 10 | Using index | 
  36.  
  37. +—-+————-+——-+——-+—————+——-+———+——+——+————-+ 
  38.  
  39. 1 row in set (0.00 sec) 

版本【5.1.48】中首先明智的選擇ind_1來完成掃描,并沒有考慮到使用主鍵(全索引掃描)來完成查詢,隨后添加ind_2,由于 ind_1的key長度是大于ind_2 key長度,所以mysql選擇更優的ind_2來完成查詢,可以看到mysql在選擇方式上也在慢慢智能了。

觀察性能:

 

 
  1. 5.1.48 
  2.  
  3. root@test 08:49:32>set profiling =1; 
  4.  
  5. Query OK, 0 rows affected (0.00 sec) 
  6.  
  7. root@test 08:49:41>select count(*) from test; 
  8.  
  9. +———-+ 
  10.  
  11. count(*) | 
  12.  
  13. +———-+ 
  14.  
  15. | 5242880 | 
  16.  
  17. +———-+ 
  18.  
  19. 1 row in set (1.18 sec) 
  20.  
  21. root@test 08:56:30>show profile cpu,block io for query 1; 
  22.  
  23. +——————————–+———-+———-+————+————–+—————+ 
  24.  
  25. | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | 
  26.  
  27. +——————————–+———-+———-+————+————–+—————+ 
  28.  
  29. | starting | 0.000035 | 0.000000 | 0.000000 | 0 | 0 | 
  30.  
  31. | checking query cache for query | 0.000051 | 0.000000 | 0.000000 | 0 | 0 | 
  32.  
  33. | Opening tables | 0.000014 | 0.000000 | 0.000000 | 0 | 0 | 
  34.  
  35. | System lock | 0.000005 | 0.000000 | 0.000000 | 0 | 0 | 
  36.  
  37. Table lock | 0.000010 | 0.000000 | 0.000000 | 0 | 0 | 
  38.  
  39. | init | 0.000015 | 0.000000 | 0.000000 | 0 | 0 | 
  40.  
  41. | optimizing | 0.000007 | 0.000000 | 0.000000 | 0 | 0 | 
  42.  
  43. statistics | 0.000015 | 0.000000 | 0.000000 | 0 | 0 | 
  44.  
  45. | preparing | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 
  46.  
  47. | executing | 0.000007 | 0.000000 | 0.000000 | 0 | 0 | 
  48.  
  49. | Sending data | 1.178452 | 1.177821 | 0.000000 | 0 | 0 | 
  50.  
  51. end | 0.000016 | 0.000000 | 0.000000 | 0 | 0 | 
  52.  
  53. | query end | 0.000005 | 0.000000 | 0.000000 | 0 | 0 | 
  54.  
  55. | freeing items | 0.000040 | 0.000000 | 0.000000 | 0 | 0 | 
  56.  
  57. | logging slow query | 0.000002 | 0.000000 | 0.000000 | 0 | 0 | 
  58.  
  59. | logging slow query | 0.000086 | 0.000000 | 0.000000 | 0 | 0 | 
  60.  
  61. | cleaning up | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | 
  62.  
  63. +——————————–+———-+———-+————+————–+—————+ 

對比性能:

 

 
  1. 5.1.45 
  2.  
  3. root@test 08:57:18>set profiling =1; 
  4.  
  5. Query OK, 0 rows affected (0.00 sec) 
  6.  
  7. root@test 08:57:21>select count(*) from test; 
  8.  
  9. +———-+ 
  10.  
  11. count(*) | 
  12.  
  13. +———-+ 
  14.  
  15. | 5242880 | 
  16.  
  17. +———-+ 
  18.  
  19. 1 row in set (1.30 sec) 
  20.  
  21. root@test 08:57:27>show profile cpu,block io for query 1; 
  22.  
  23. +——————————–+———-+———-+————+————–+—————+ 
  24.  
  25. | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | 
  26.  
  27. +——————————–+———-+———-+————+————–+—————+ 
  28.  
  29. | starting | 0.000026 | 0.000000 | 0.000000 | 0 | 0 | 
  30.  
  31. | checking query cache for query | 0.000041 | 0.000000 | 0.000000 | 0 | 0 | 
  32.  
  33. | Opening tables | 0.000014 | 0.000000 | 0.000000 | 0 | 0 | 
  34.  
  35. | System lock | 0.000005 | 0.000000 | 0.000000 | 0 | 0 | 
  36.  
  37. Table lock | 0.000008 | 0.000000 | 0.000000 | 0 | 0 | 
  38.  
  39. | init | 0.000015 | 0.000000 | 0.000000 | 0 | 0 | 
  40.  
  41. | optimizing | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | 
  42.  
  43. statistics | 0.000014 | 0.000000 | 0.000000 | 0 | 0 | 
  44.  
  45. | preparing | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 
  46.  
  47. | executing | 0.000007 | 0.000000 | 0.000000 | 0 | 0 | 
  48.  
  49. | Sending data | 1.294178 | 1.293803 | 0.000000 | 0 | 0 | 
  50.  
  51. end | 0.000016 | 0.000000 | 0.000000 | 0 | 0 | 
  52.  
  53. | query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
  54.  
  55. | freeing items | 0.000040 | 0.000000 | 0.001000 | 0 | 0 | 
  56.  
  57. | logging slow query | 0.000002 | 0.000000 | 0.000000 | 0 | 0 | 
  58.  
  59. | logging slow query | 0.000080 | 0.000000 | 0.000000 | 0 | 0 | 
  60.  
  61. | cleaning up | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | 
  62.  
  63. +——————————–+———-+———-+————+————–+—————+ 

從上面的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。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 潼关县| 乌苏市| 南丰县| 南昌县| 彩票| 宁陕县| 平凉市| 特克斯县| 西吉县| 鹿邑县| 长沙市| 哈密市| 疏勒县| 平远县| 双柏县| 九龙城区| 胶州市| 牟定县| 白河县| 工布江达县| 临沭县| 玉龙| 福清市| 拉萨市| 斗六市| 马公市| 怀安县| 松江区| 吉水县| 辉县市| 临高县| 花垣县| 奇台县| 惠州市| 普兰店市| 桦甸市| 来宾市| 保德县| 菏泽市| 潼南县| 涿鹿县|