簡略剖析MySQL中的primary key功效。本站提示廣大學習愛好者:(簡略剖析MySQL中的primary key功效)文章只能為提供參考,不一定能成為您想要的結果。以下是簡略剖析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。