mysql8.0 之 sql 优化《三B》 之 优化范围查询 总览 总结
單部分索引的范圍訪問方法
單部分索引的范圍條件的定義如下:
- 對于這兩種BTREE和?HASH索引,使用時具有恒定值的關鍵部分的比較是一個范圍條件 = <=>,in(),is null or,is not null運營商。
- 另外,對于BTREE索引,使用時具有恒定值的關鍵部分的比較是一個范圍條件 >,<,>=,<=,between,!=,<>運營商,或者like比較,如果該參數 like是一個常數字符串不與通配符開始。
- 對于所有索引類型,多個范圍條件與范圍條件組合?or?或?AND形成范圍條件。
?
以下是WHERE子句中具有范圍條件的查詢的一些示例:
SELECT * FROM t1WHERE key_col > 1AND key_col < 10;SELECT * FROM t1WHERE key_col = 1OR key_col IN (15,18,20);SELECT * FROM t1WHERE key_col LIKE 'ab%'OR key_col BETWEEN 'bar' AND 'foo';?
MySQL嘗試從WHERE每個可能索引的子句中提取范圍條件?。在提取過程期間,丟棄不能用于構建范圍條件的條件,組合產生重疊范圍的條件,并且去除產生空范圍的條件。
請考慮以下語句,其中?key1是索引列?nonkey且未編入索引:
SELECT * FROM t1 WHERE(key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR(key1 < 'bar' AND nonkey = 4) OR(key1 < 'uux' AND key1 > 'z');?
密鑰的提取過程key1如下:
從原始WHERE條款開始:
(key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR (key1 < 'bar' AND nonkey = 4) OR (key1 < 'uux' AND key1 > 'z')刪除nonkey = 4并key1 LIKE '%b'因為它們不能用于范圍掃描。刪除它們的正確方法是用它們替換它們TRUE,這樣我們在進行范圍掃描時不會錯過任何匹配的行。用TRUE產量替換它們:
(key1 < 'abc' AND (key1 LIKE 'abcde%' OR TRUE)) OR (key1 < 'bar' AND TRUE) OR (key1 < 'uux' AND key1 > 'z')折疊條件始終為真或假:
-
(key1 LIKE 'abcde%' OR TRUE)?總是如此
-
(key1 < 'uux' AND key1 > 'z')?總是假的
用常數替換這些條件會產生:
(key1 < 'abc' AND TRUE) OR (key1 < 'bar' AND TRUE) OR (FALSE)刪除不必要的TRUE和?FALSE常量會產生:
(key1 < 'abc') OR (key1 < 'bar')將重疊間隔組合成一個會產生用于范圍掃描的最終條件:
(key1 < 'bar')通常(并且如前面的示例所示),用于范圍掃描的條件比該WHERE子句的限制性更小。MySQL執行額外的檢查以過濾掉滿足范圍條件但不滿足完整WHERE子句的行。
范圍條件提取算法可以處理?任意深度的嵌套 and/or構造,其輸出不依賴于條件在WHERE子句中出現的順序?。
?
多部分索引的范圍訪問方法
以下描述更詳細地說明了范圍條件如何適用于多部分索引。
-
對于HASH索引,可以使用包含相同值的每個間隔。這意味著只能為以下形式的條件生成間隔:
key_part1 cmp const1 AND key_part2 cmp const2 AND ... AND key_partN cmp constN;這里const1,?const2...是常數,cmp是一個?=,?<=>或者IS NULL比較運營商,以及條件覆蓋所有指數部分。(也就是說,有一些N?條件,一個用于N-part索引的每個部分?。)例如,以下是三部分HASH索引的范圍條件?:
key_part1 = 1 AND key_part2 IS NULL AND key_part3 = 'foo'
例子:
key_part1 = 'foo' AND key_part2 >= 10 AND key_part3 > 10單個間隔是:
('foo',10,-inf) < (key_part1,key_part2,key_part3) < ('foo',+inf,+inf)例子:
(key_part1 = 1 AND key_part2 < 2) OR (key_part1 > 5) 間隔是:(1,-inf) < (key_part1,key_part2) < (1,2) (5,-inf) < (key_part1,key_part2)?
例子:
key_part1 >= 1 AND key_part2 < 2 但是,事實上,條件轉換為:key_part1 >= 1 AND key_part2 IS NOT NULL?
多值比較的等價范圍優化
col_name IN(val1, ..., valN) col_name = val1 OR ... OR col_name = valN在MySQL 8.0中,對于滿足所有這些條件的查詢,可以進行索引潛水跳過:
-
查詢用于單個表,而不是多個表的連接。
-
存在單索引FORCE INDEX索引提示。我們的想法是,如果強制使用索引,那么從潛在的索引中獲取額外開銷就無法獲得任何好處。
-
該索引不是唯一的而不是?FULLTEXT索引。
-
沒有子查詢。
-
不DISTINCT,GROUP BY或ORDER BY條款存在。
?
跳過掃描范圍訪問方法
CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2)); INSERT INTO t1 VALUES(1,1), (1,2), (1,3), (1,4), (1,5),(2,1), (2,2), (2,3), (2,4), (2,5); INSERT INTO t1 SELECT f1, f2 + 5 FROM t1; INSERT INTO t1 SELECT f1, f2 + 10 FROM t1; INSERT INTO t1 SELECT f1, f2 + 20 FROM t1; INSERT INTO t1 SELECT f1, f2 + 40 FROM t1; ANALYZE TABLE t1;EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40;對于前面顯示的數據集,算法的運行方式如下:
獲取第一個關鍵部分(f1 = 1)的第一個不同值。
根據第一個和第二個關鍵部分構造范圍(f1 = 1 AND f2 > 40)。
執行范圍掃描。
獲取第一個關鍵部分(f1 = 2)的下一個不同值。
根據第一個和第二個關鍵部分構造范圍(f1 = 2 AND f2 > 40)。
執行范圍掃描。
行構造函數表達式的范圍優化
優化器能夠將范圍掃描訪問方法應用于此表單的查詢:
SELECT ... FROM t1 WHERE ( col_1, col_2 ) IN (( 'a', 'b' ), ( 'c', 'd' ));優化為:
SELECT ... FROM t1 WHERE ( col_1 = 'a' AND col_2 = 'b' ) OR ( col_1 = 'c' AND col_2 = 'd' );要使優化器使用范圍掃描,查詢必須滿足以下條件:
- 只使用IN()謂詞,而不是NOT IN()。
- 在IN()謂詞的左側?,行構造函數僅包含列引用。
- 在IN()謂詞的右側?,行構造函數僅包含運行時常量,這些常量是在執行期間綁定到常量的文字或本地列引用。
- 在IN()謂詞的右側?,有多個行構造函數。
?
限制內存使用范圍優化
要控制范圍優化程序可用的內存,請使用?range_optimizer_max_mem_size系統變量:
-
值為0表示“?無限制。”
-
值大于0時,優化程序會在考慮范圍訪問方法時跟蹤消耗的內存。如果要超過指定的限制,則放棄范圍訪問方法,并考慮其他方法,包括全表掃描。這可能不太理想。如果發生這種情況,會發生以下警告(N當前?range_optimizer_max_mem_size值在哪里?):
要估計處理范圍表達式所需的內存量,請使用以下準則:
-
對于諸如以下的簡單查詢,其中有一個候選鍵用于范圍訪問方法,每個謂詞組合OR?使用大約230個字節:
SELECT COUNT(*) FROM t WHERE a=1 OR a=2 OR a=3 OR .. . a=N; -
類似地,對于諸如以下的查詢,每個謂詞組合AND使用大約125個字節:
SELECT COUNT(*) FROM t WHERE a=1 AND b=1 AND c=1 ... N; -
對于帶in()謂詞的查詢:
SELECT COUNT(*) FROM t WHERE a IN (1,2, ..., M) AND b IN (1,2, ..., N);in()列表?中的每個文字值都?計為一個謂詞組合or。如果有兩個in()?列表,則組合的謂詞 or數是每個列表中文字值的數量的乘積。因此,與or前一種情況相結合的謂詞數?是?M×?N。
?
?
優化總篇:https://blog.csdn.net/weixin_42749765/article/details/88223273
?
?
文章持續更新,轉發表明出處,方便更新!
?
?
?
?
總結
以上是生活随笔為你收集整理的mysql8.0 之 sql 优化《三B》 之 优化范围查询 总览 总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 功能测试的类型之Alpha和Beta测试
- 下一篇: 【Go】用 Go 访问 Redis