<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
TIPS:
-- 建立測試表 DROP TABLE IF EXISTS `test_idx`; CREATE TABLE `test_idx` ( `id` int(11) NOT NULL AUTO_INCREMENT, `unique_idx` int(11) NOT NULL, `notnull_idx` int(11) NOT NULL, `str_idx` varchar(20) DEFAULT NULL, `normal_idx` int(11) DEFAULT NULL, `str_col` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_unique_idx` (`unique_idx`), KEY `idx_str_idx` (`str_idx`), KEY `idx_normal_idx` (`normal_idx`) USING BTREE ) DEFAULT CHARSET=utf8; -- 插入幾條測試資料,因為當表裡沒有資料時,部分使用到索引的情況會失效。 INSERT INTO test_idx VALUES (1,1,'1',1,'111'), (2,2,'2',2,'222'), (3,3,'3',3,'333')
1、使用like且在左邊有“%”。
-- 無法使用索引 EXPLAIN select * from test_idx where bid like '%1%'; -- 可以使用索引 EXPLAIN select * from test_idx where bid like '1%';
2、隱式型別轉換,索引欄位與條件或關聯欄位的型別不一致。
-- 無法使用索引 EXPLAIN select * from test_idx where bid = 1; -- 可以使用索引 EXPLAIN select * from test_idx where bid = '1';
3、條件中對索引列進行運算或使用函數
-- 無法使用索引 EXPLAIN SELECT * FROM test_idx WHERE SUBSTR(bid, 1) = '1'; EXPLAIN SELECT * FROM test_idx WHERE id - 1 = 1; -- 可以使用索引 EXPLAIN SELECT * FROM test_idx WHERE id = 4 - 2; EXPLAIN SELECT * FROM test_idx WHERE id = TIME_TO_SEC(1);
4、不可空索引使用 is not null,僅當查詢列只有該索引列時會使用索引
-- 無法使用索引 EXPLAIN SELECT * FROM test_idx WHERE notnull_idx IS NOT NULL; -- 可以使用索引 EXPLAIN SELECT notnull_idx FROM test_idx WHERE notnull_idx IS NOT NULL; EXPLAIN SELECT * FROM test_idx WHERE normal_idx IS NOT NULL;
5、使用OR且存在非索引列
-- 無法使用索引 EXPLAIN SELECT * FROM test_idx WHERE id > 1 OR str_col = '1'; -- 使用OR時,OR包含的所有列必須都是獨立索引才有可能用到索引
6、使用 NOT IN、IN、IS NULL、IS NOT NULL,且返回值中不止包含條件索引列。
-- 部分情況下可以使用索引 -- 當表裡沒有資料時不使用索引 -- 本次測試當後面的條件查詢的返回值大於等於總資料50%時不使用索引;少於總資料50%則使用索引 -- 該資料不一定準,這跟資料總量、表統計資訊等會有不同的表現,因此還是得看最終優化器的選擇! EXPLAIN SELECT * FROM test_idx WHERE normal_idx IN (1,2); EXPLAIN SELECT * FROM test_idx WHERE normal_idx NOT IN (1,2); EXPLAIN SELECT * FROM test_idx WHERE normal_idx IS NULL; EXPLAIN SELECT * FROM test_idx WHERE normal_idx IS NOT NULL;
拓展:
7、使用非主鍵範圍條件查詢時,部分情況索引失效。
-- 部分情況下可以使用索引 -- 當表裡沒有資料時不使用索引 -- 本次測試當範圍條件查詢的返回值大於等於總資料50%時不使用索引;少於總資料50%則使用索引 -- 該資料不一定準,這跟資料總量、表統計資訊等會有不同的表現,因此還是得看最終優化器的選擇! EXPLAIN SELECT * FROM test_idx WHERE normal_idx > 1; EXPLAIN SELECT * FROM test_idx WHERE normal_idx <= 1; EXPLAIN SELECT * FROM test_idx WHERE normal_idx BETWEEN 0 AND 1; EXPLAIN SELECT * FROM test_idx WHERE normal_idx BETWEEN 2 AND 5;
8、MySQL5.7,使用 IS NOT NULL或 IS NULL 部分情況下索引失效。
-- 部分情況下可以使用索引 -- 當表裡沒有資料時索引失效 -- 本次測試條件查詢的返回值大於等於總資料50%時不使用索引;少於總資料50%則使用索引 -- 該資料不一定準,這跟資料總量、表統計資訊等會有不同的表現,因此還是得看最終優化器的選擇! EXPLAIN SELECT normal_idx FROM test_idx WHERE normal_idx IS NOT NULL; EXPLAIN SELECT normal_idx FROM test_idx WHERE normal_idx IS NULL;
9、MySQL5.7,使用 != 或 IN 或 NOT IN 部分情況下索引失效
-- 部分情況下可以使用索引 -- 本次測試當條件查詢的返回值大於等於總資料50%時不使用索引;少於總資料50%則使用索引 -- 該資料不一定準,這跟資料總量、表統計資訊等會有不同的表現,因此還是得看最終優化器的選擇! EXPLAIN SELECT * FROM test_idx WHERE normal_idx IN (1); EXPLAIN SELECT * FROM test_idx WHERE normal_idx NOT IN (1); -- 使用 != 也跟資料的篩選率有關,具體數值不能確定(但肯定篩選率要>50%)。視實際情況而定,還得看優化器的選擇。 -- 可能使用索引,也可能不使用: EXPLAIN SELECT * FROM test_idx WHERE normal_idx IN (1); -- 可以使用索引,但是這裡不是使用索引去查資料,而且是去查索引鍵值。 -- 即先根據該索引去查其他索引的值,再根據查出來的索引值去查資料。 -- extra中顯示 Using index 均表示該情況。 EXPLAIN SELECT normal_idx FROM test_idx WHERE normal_idx IN (1); EXPLAIN SELECT normal_idx FROM test_idx WHERE normal_idx NOT IN (1);
10、MySQL5.7,表關聯時,關聯欄位字元集不一致會導致索引失效。
-- 建立一個字元集與之前的表不一致的表 CREATE TABLE `test_idx2` ( `id` int(11) NOT NULL AUTO_INCREMENT, `unique_idx` int(11) DEFAULT NULL, `notnull_idx` int(11) NOT NULL, `str_idx` varchar(20) DEFAULT NULL, `normal_idx` int(11) DEFAULT NULL, `str_col` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `idx_unique_idx` (`unique_idx`), KEY `idx_str_idx` (`str_idx`), KEY `idx_normal_idx` (`normal_idx`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 插入資料,如果沒有資料,在MySQL8.0中索引也會失效 INSERT INTO test_idx2 values (1,1,1,'1',1,'11'), (2,2,2,'2',2,'22'), (3,3,3,'3',3,'33'); -- 無法使用索引 EXPLAIN SELECT * FROM test_idx t1 LEFT JOIN test_idx2 t2 ON t1.str_idx = t2.str_idx; -- 子查詢可以使用索引,但是這裡不是使用索引去查資料,而且是去查索引鍵值。 -- 即先根據該索引去查其他索引的值,再根據查出來的索引值去查資料。 -- extra中顯示 Using index 均表示該情況。 EXPLAIN SELECT * FROM test_idx t1 WHERE t1.id = (SELECT id FROM test_idx2 WHERE t1.str_idx = str_idx LIMIT 1);
11、MySQL5.7,表關聯時,關聯欄位字元集排序規則不一致會導致索引失效。
-- 當使用字串型別索引進行關聯或用於子查詢時會報錯: -- 1267 - Illegal mix of collations (utf8mb4_german2_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for operation '=' -- 翻譯:操作「=」的排序規則(utf8mb4_german2_ci,隱式)和(utf8mb4_general_ci,隱式)的非法混合 -- 使用其他型別索引進行關聯時,索引失效。 -- 使用其他型別索引進行子查詢時,可以使用索引。 -- 這裡就不做舉例了,實際情況下出現的可能性不大。
1、使用OR且第一個條件是範圍查詢,且返回值中不止包含條件索引列。
-- 無法使用索引 EXPLAIN SELECT * FROM test_idx WHERE id > 1 OR normal_idx = 1; -- 部分情況下可以使用索引 -- 當表裡沒有資料時不使用索引 -- 當後面的條件查詢的返回值超過總資料50%時不使用索引;少於總資料50%則使用索引 EXPLAIN SELECT * FROM test_idx WHERE id = 1 OR normal_idx > 2; -- 由於一次查詢中一張表只能使用一個索引,所以優化器是將該sql優化成UNION執行的。 -- 因此我們可以直接將OR語句改成UNION語句(如果肯定兩個條件不會出現重複返回值,則可以使用UNION ALL,UNOIN在查詢後還需要做一次去重操作,UNOIN ALL則不需要,可以進一步提高查詢速度)。 EXPLAIN SELECT * FROM test_idx WHERE id = 1 UNION ALL SELECT * FROM test_idx WHERE normal_idx > 2;
2、 MySQL5.7,使用OR且存在條件是範圍查詢,且返回值中不止包含條件索引列。
-- 無法使用索引 EXPLAIN SELECT * FROM test_idx WHERE id > 1 OR normal_idx = 1; EXPLAIN SELECT * FROM test_idx WHERE id = 1 OR normal_idx > 1;
3、組合索引
-- 建立測試表 CREATE TABLE test_idx4 ( id INT ( 11 ) PRIMARY KEY auto_increment, col1 VARCHAR ( 11 ) DEFAULT NULL, col2 VARCHAR ( 11 ) DEFAULT NULL, col3 VARCHAR ( 11 ) DEFAULT NULL, col4 VARCHAR ( 11 ) DEFAULT NULL, KEY idx_col1_col2_col3( col1, col2, col3 ) USING BTREE ); -- 插入測試資料 INSERT INTO test_idx4 VALUES ( 1, '1', '1', '1', '1' ), ( 2, '1', '1', '1', '1' ), ( 3, '1', '1', '1', '1' ), ( 4, '1', '1', '1', '1' ); -- 最左匹配原則:只要查詢條件中帶有組合索引最左邊的列(此處即 col1) , 那麼查詢就會使用到索引。 -- 所以想讓組合索引失效很簡單,條件中不包含索引最左邊的列(此處即 col1), 則索引失效。
擴充套件:
SELECT col2,col3 FROM test_idx4 SELECT col2,col3 FROM test_idx4 WHERE col2 = '1' AND col3='2'
上述所有可能用到可能沒用到索引的情況,並不是一定的!導致索引失效的閾值也不一定100%準確,畢竟不同資料型別、不同資料量的情況下,MySQL的優化器的選擇可能不同。但可以肯定的是,同樣一條語句,可能由於篩選率等原因導致索引失效。
所有簡單查詢(執行計劃中 select_type = simple),只要where條件中有索引列(無論什麼條件),且返回值中只包含該索引列(和主鍵),都會用到索引。根據執行計劃中的extra可以區分索引的用途:
1、extra = Using index,表示索引覆蓋。
2、extra = Using index, Using where,表示存在回表操作。
拓展:
為什麼只要返回值只包含索引和主鍵就會用到索引?
眾所周知,InnoDB儲存資料是通過B+樹結構儲存的。且只有主鍵索引所在的B+樹的葉子節點會儲存實際資料,其他節點只儲存主鍵值,這種資料與索引在一起的索引我們稱之為聚簇索引。
二級索引(非主鍵索引)的所有節點除了儲存索引列的值外還會儲存主鍵的值。
所以當我們通過二級索引查詢資料時,第一步先通過二級索引查詢到對應的主鍵值;再通過主鍵值到主鍵索引中查詢對應的實際資料,這個過程我們稱之為回表。
而回表操作是隨機IO,所以效能較差,當需要回表的資料量比較大時,優化器可能就會選擇不走索引,直接全表掃描,因為走全表是順序IO,指不定走全表比走索引還快。(這也解釋了為什麼同樣的SQL,表資料不同查詢策略也不同)
其中一個特殊情況是當我們的查詢只涉及到索引列和主鍵的時候,我們就不需要再回表查詢實際資料了,因為二級索引中儲存了主鍵和索引列的資料,這個時候就肯定會走索引了。
在複製其他地方提供的sql建表指令碼時,注意其字元集和排序規則是否跟自己資料庫預設的一致,否則可能出現索引失效的問題。
不同版本不同情況下,索引的使用情況不一致。上文提到的可能使用可能不使用的情況是由MySQL的優化器決定的,可能還會有其他情況下優化器也不使用索引,此時我們可以強制指定需要使用的索引:
-- 通過 force index(IDX_NAME) 強制指定索引 EXPLAIN SELECT * FROM test_idx force index (idx_notnull_idx) WHERE notnull_idx BETWEEN 1 AND 2;
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45