查看表主鍵信息
## 查看表主鍵信息 SELECT t.TABLE_NAME, t.CONSTRAINT_TYPE, c.COLUMN_NAME, c.ORDINAL_POSITION FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS t, INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS c WHERE t.TABLE_NAME = c.TABLE_NAME AND t.CONSTRAINT_TYPE = 'PRIMARY KEY' AND t.TABLE_NAME='<TABLE_NAME>' AND t.TABLE_SCHEMA='<TABLE_SCHEMA>';
查看無主鍵表
## 查看無主鍵表 SELECT table_schema, table_name,TABLE_ROWS FROM information_schema.tables WHERE (table_schema, table_name) NOT IN ( SELECT DISTINCT table_schema, table_name FROM information_schema.columns WHERE COLUMN_KEY = 'PRI' ) AND table_schema NOT IN ('sys', 'mysql', 'information_schema', 'performance_schema');
無主鍵表
在Innodb存儲引擎中,每張表都會有主鍵,數據按照主鍵順序組織存放,該類表成為索引組織表 Index Ogranized Table
如果表定義時沒有顯示定義主鍵,則會按照以下方式選擇或創建主鍵:
a) 先判斷表中是否有"非空的唯一索引",如果有 1) 如果僅有一條"非空唯一索引",則該索引為主鍵 2) 如果有多條"非空唯一索引",根據索引索引的先后順序,選擇第一個定義的非空唯一索引為主鍵。 b) 如果表中無"非空唯一索引",則自動創建一個6字節大小的指針作為主鍵。
如果主鍵索引只有一個索引鍵,那么可以使用_rowid來顯示主鍵,如:
## 刪除測試表 DROP TABLE IF EXISTS tb2001; ## 創建測試表 CREATE TABLE `tb2001` ( `id` int(11) NOT NULL, `c1` int(11) DEFAULT NULL, UNIQUE uni_id (id), INDEX idx_c1(c1) ) ENGINE = InnoDB CHARSET = utf8; ## 插入測試數據 INSERT INTO tb2001 (id, c1) SELECT 1, 1; INSERT INTO tb2001 (id, c1) SELECT 2, 2; INSERT INTO tb2001 (id, c1) SELECT 4, 4; ## 查看數據和_rowid SELECT *, _rowid FROM tb2001; +----+------+--------+ | id | c1 | _rowid | +----+------+--------+ | 1 | 1 | 1 | | 2 | 2 | 2 | | 4 | 4 | 4 | +----+------+--------+
可以發現,上面的_rowid與id的值相同,因為id列是表中第一個唯一且NOT NULL的索引。
強制主鍵索引
由於主鍵索引只能為PRIMARY:
SHOW INDEXES IN tb2001 \G *************************** 1. row *************************** Table: tb2001 Non_unique: 0 Key_name: PRIMARY Seq_in_index: 1 Column_name: id Collation: A Cardinality: 2 Sub_part: NULL Packed: NULL Null: Index_type: BTREE Comment: Index_comment:
因此在強制走主鍵索引FORCE INDEX(PRIMARY)時,使用:
SELECT * FROM tb2001 FORCE INDEX(PRIMARY) WHERE C1=2;
非聚集索引中的聚集索引鍵
在MySQL 5.6.9版本前,Innodb的非聚集索引中包含聚集索引的索引鍵,但只起到通過非聚集索引定位記錄的作用,但在MySQL 5.6.9之后版本中,優化器會考慮非聚集索引中包含的聚集索引鍵來提升查詢性能,並提供優化器選項use_index_extensions來開啟或關閉該特性。
假設有表TB1(ID,C1,C2), ID為主鍵聚集索引,然后在列C1建立索引IDX_C1(C1):
在MySQL 5.6版本前,索引類似於IDX_C1(C1) INCLUDE(ID);
在MySQL 5.6版本中,索引類似於IDX_C1(C1,ID);
無論是MySQL 5.5還是MySQL 5.6版本中,非聚集索引上的數據都是先按照非聚集索引鍵在按照聚集索引鍵進行排序,即在非聚集索引鍵上值相同的記錄會按照聚集索引進行排序。
對於查詢:
SELECT * FROM TB1 WHERE C1='ABC' AND ID>10 AND ID<1000
在MySQL 5.5版本中,需要按照索引IDX_C1掃描所有C1='ABC'的記錄,再根據ID進行過濾。
在MySQL 5.6版本中,進行按照索引IDX_C1就可以先定位C1='ABC' AND ID>10的第一條記錄,再順序掃描至C1='ABC' AND ID<1000的記錄,有效減少掃描的數據量。
對於查詢:
SELECT * FROM TB1 WHERE C1='ABC' ORDER BY ID LIMIT 1
如果滿足C1='ABC'的記錄數較多,那么查詢在MySQL 5.5版本就會性能極差,而在MySQL 5.6版本中變得性能極好,MySQL 5.5版本可以將IDX_C1(C1)優化為 IDX(C1,ID)。
在MySQL 5.5.14版本進行測試,准備測試數據:
## 刪除測試表 DROP TABLE IF EXISTS tb2001; ## 創建測試表 CREATE TABLE `tb2001` ( `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `c1` int(11) DEFAULT NULL, `c2` int(11) DEFAULT NULL, INDEX idx_c1(c1), INDEX idx_c2(c2,id) ) ENGINE = InnoDB CHARSET = utf8; ## 插入測試數據(10萬左右) ## 如果information_schema.columns數據較少,可以重復多次 INSERT INTO tb2001 (c1,c2) SELECT 1,1 from information_schema.columns;
測試1:
## 測試SQL 1 SELECT c1,id FROM tb2001 FORCE INDEX(idx_c1) WHERE C1=1 and id<2;
## 執行時間超過20MS ## 對應執行計划為: *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tb2001 type: ref possible_keys: idx_c1 key: idx_c1 key_len: 5 ref: const rows: 44196 Extra: Using where; Using index ## 對應PROFILING數據為: +----------------------+----------+----------+------------+--------------+---------------+-------+ | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | Swaps | +----------------------+----------+----------+------------+--------------+---------------+-------+ | starting | 0.000039 | 0.000000 | 0.000000 | 0 | 0 | 0 | | checking permissions | 0.000007 | 0.000000 | 0.000000 | 0 | 0 | 0 | | Opening tables | 0.000011 | 0.000000 | 0.000000 | 0 | 0 | 0 | | System lock | 0.000008 | 0.000000 | 0.000000 | 0 | 0 | 0 | | init | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 0 | | optimizing | 0.000009 | 0.000000 | 0.000000 | 0 | 0 | 0 | | statistics | 0.000041 | 0.000000 | 0.000000 | 0 | 0 | 0 | | preparing | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 0 | | executing | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 0 | | Sending data | 0.020529 | 0.019997 | 0.000000 | 0 | 0 | 0 | | end | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | 0 | | query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 0 | | closing tables | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | 0 | | freeing items | 0.000020 | 0.000000 | 0.000000 | 0 | 0 | 0 | | logging slow query | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 0 | | cleaning up | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 0 | +----------------------+----------+----------+------------+--------------+---------------+-------+
測試2:
## 測試SQL: SELECT c2,id FROM tb2001 FORCE INDEX(idx_c2) WHERE C2=1 and id<2; ##執行時間2ms ## 對應執行計划為: *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tb2001 type: range possible_keys: idx_c2 key: idx_c2 key_len: 9 ref: NULL rows: 1 Extra: Using where; Using index ## 對應PROFILING數據為: +----------------------+----------+----------+------------+--------------+---------------+-------+ | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | Swaps | +----------------------+----------+----------+------------+--------------+---------------+-------+ | starting | 0.000042 | 0.000000 | 0.000000 | 0 | 0 | 0 | | checking permissions | 0.000007 | 0.000000 | 0.000000 | 0 | 0 | 0 | | Opening tables | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 0 | | System lock | 0.000007 | 0.000000 | 0.000000 | 0 | 0 | 0 | | init | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 0 | | optimizing | 0.000008 | 0.000000 | 0.000000 | 0 | 0 | 0 | | statistics | 0.000033 | 0.000000 | 0.000000 | 0 | 0 | 0 | | preparing | 0.000011 | 0.000000 | 0.000000 | 0 | 0 | 0 | | executing | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 0 | | Sending data | 0.000031 | 0.000000 | 0.000000 | 0 | 0 | 0 | | end | 0.000005 | 0.000000 | 0.000000 | 0 | 0 | 0 | | query end | 0.000005 | 0.000000 | 0.000000 | 0 | 0 | 0 | | closing tables | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | 0 | | freeing items | 0.000022 | 0.000000 | 0.000000 | 0 | 0 | 0 | | logging slow query | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 0 | | cleaning up | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 0 | +----------------------+----------+----------+------------+--------------+---------------+-------+
參考鏈接:https://dev.mysql.com/doc/refman/5.6/en/index-extensions.html
