1. 程式人生 > 其它 >bcp 不能呼叫where 子句_Mysql Select語句之子句與範圍優化

bcp 不能呼叫where 子句_Mysql Select語句之子句與範圍優化

技術標籤:bcp 不能呼叫where 子句group子句返回結果中會有一行對null值的統計mysql or優化predicates.add如何使用or語句使用的select語句具有不同的列數如何不使用where子句從表中匯入行的子集?

37e3bd14e1ecb6be4000972d43dba806.png

點選上方「Java有貨」關注我們

76ba4d84f8833cb32104de92425c4d2d.gif技術交流群新增方式

+

新增小編微信:372787553,備註:進群帶您進入Java技術交流群優化SELECT語句 優化查詢的主要考慮因素是:
  • 為了使慢速SELECT ... WHERE查詢更快,首先要檢查的是是否可以新增索引。在WHERE子句中使用的列上設定索引,以加快評估,過濾和最終檢索結果的速度。為避免浪費磁碟空間,請構建一小組索引,以加快應用程式中使用的許多相關查詢的速度。對於使用連線和外來鍵之類的功能引用不同表的查詢,索引尤其重要 。您可以使用該EXPLAIN
    語句來確定用於的索引 SELECT
  • 隔離和調整查詢中花費過多時間的任何部分,例如函式呼叫。根據查詢的結構方式,可以對結果集中的每一行呼叫一次函式,甚至可以對錶中的每一行呼叫一次函式,從而極大地提高了效率。
  • 最小化 查詢中全表掃描的次數 ,特別是對於大表。
  • 通過ANALYZE TABLE定期使用該語句來使表統計資訊保持最新 ,使得優化器具有構造有效執行計劃所需的資訊。
  • 瞭解特定於每個表的儲存引擎的調整技術,索引技術和配置引數。InnoDBMyISAM有兩套準則的實現和維持查詢高效能。
  • 您可以InnoDB使用優化InnoDB只讀事務”中的技術優化表的 單查詢事務 。
  • 避免以難以理解的方式轉換查詢,尤其是在優化程式自動執行某些相同轉換的情況下。
  • 如果使用基本準則之一不能輕鬆解決效能問題,請通過閱讀EXPLAIN計劃並調整索引,WHERE子句,連線子句等來調查特定查詢的內部詳細資訊 。
  • 調整MySQL用於快取的記憶體區域的大小和屬性。通過有效地使用 InnoDB 緩衝池, MyISAM鍵快取記憶體和MySQL查詢快取記憶體,重複查詢的執行速度更快,因為第二次及以後都從記憶體中檢索了結果。
  • 即使對於使用快取區域快速執行的查詢,您仍可能會進一步優化,以使它們需要更少的快取,從而使您的應用程式更具可伸縮性。可伸縮性意味著您的應用程式可以處理更多的併發使用者,更大的請求等,而不會導致效能大幅下降。
  • 處理鎖定問題,其中其他會話同時訪問表可能會影響查詢速度。
WHERE子句優化 這些示例使用 SELECT 語句,但是相同的優化適用 WHEREDELETEUPDATE 語句中的子句 。 您可能會想重寫查詢以使算術運算更快,同時又犧牲了可讀性。由於MySQL自動進行類似的優化,因此您通常可以避免這項工作,而將查詢保留為更易於理解和維護的形式。MySQL執行的一些優化如下:
  • 刪除不必要的括號:
      ((a AND b) AND c OR (((a AND b) AND (c AND d)))) -> (a AND b AND c) OR (a AND b AND c AND d)
  • 恆定摺疊:
      (aAND b=c) AND a=5 -> b>5 AND b=c AND a=5
  • 恆定條件消除:
      (b>=5 AND b=5) OR (b=6 AND 5=5) OR (b=7 AND 5=6) -> b=5 OR b=6
  • 索引使用的常量表達式僅計算一次。
  • COUNT(*)上沒有一個單一的表WHERE是從該表資訊直接檢索MyISAMMEMORY表。NOT NULL當僅與一個表一起使用時,對於任何表示式也可以執行此操作。
  • 早期檢測無效的常量表達式。MySQL快速檢測到某些 SELECT語句是不可能的,並且不返回任何行。
  • HAVING WHERE如果您不使用GROUP BY或彙總功能(COUNT()MIN()等),則與合併 。
  • 對於連線中的每個表,WHERE構造一個更簡單 WHERE的表以獲得表的快速 評估,並儘快跳過行。
  • 在查詢中的任何其他表之前,首先讀取所有常量表。常量表可以是以下任意一個:以下所有表均用作常量表:
    SELECT * FROM t WHERE primary_key=1;SELECT * FROM t1,t2 WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
    • 空表或具有一行的表。
    • 與a 或 索引WHERE 上的子句一起使用的表,其中所有索引部分都與常量表達式進行比較,並定義為。PRIMARY KEY UNIQUE NOT NULL
  • 通過嘗試所有可能的方法,找到用於聯接表的最佳聯接組合。如果ORDER BYand GROUP BY子句中的所有列 都來自同一表,則在連線時優先使用該表。
  • 如果有一個ORDER BY子句和另一個GROUP BY子句,或者如果 ORDER BYGROUP BY 包含聯接佇列中第一個表以外的表中的列,則會建立一個臨時表。
  • 如果使用SQL_SMALL_RESULT 修飾符,MySQL將使用記憶體中的臨時表。
  • 查詢每個表索引,並使用最佳索引,除非優化程式認為使用表掃描更有效。一次使用掃描是基於最佳索引是否跨越了表的30%以上,但是固定百分比不再決定使用索引還是掃描。現在,優化器更加複雜,其估計基於其他因素,例如表大小,行數和I / O大小。
  • 在某些情況下,MySQL甚至可以在不查詢資料檔案的情況下從索引中讀取行。如果索引中使用的所有列都是數字,則僅索引樹用於解析查詢。
  • 在輸出每一行之前,HAVING將跳過不匹配該子句的那些行 。
快速查詢的一些示例:
SELECT COUNT(*) FROM tbl_name;SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;SELECT MAX(key_part2) FROM tbl_name WHERE key_part1=constant;SELECT ... FROM tbl_name ORDER BY key_part1,key_part2,... LIMIT 10;SELECT ... FROM tbl_name ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;
假設索引列是數字,MySQL僅使用索引樹來解析以下查詢:
SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;SELECT COUNT(*) FROM tbl_name WHERE key_part1=val1 AND key_part2=val2;SELECT key_part2 FROM tbl_name GROUP BY key_part1;
以下查詢使用索引來按排序順序檢索行,而無需單獨的排序遍歷:
SELECT ... FROM tbl_name ORDER BY key_part1,key_part2,... ;SELECT ... FROM tbl_name ORDER BY key_part1 DESC, key_part2 DESC, ... ;
範圍優化 range 訪問方法使用單個索引來檢索包含一個或若干個索引值的時間間隔內錶行的子集。它可以用於單部分或多部分索引。以下各節描述了優化器使用範圍訪問的條件。
單部分索引的範圍訪問方法
對於單部分索引,索引值間隔可以方便地由條款中的相應條件 WHERE 表示,稱為 範圍條件, 而不是“ 間隔”。” 單部分索引的範圍條件的定義如下:
  • 對於這兩種BTREEHASH索引,使用時具有恆定值的關鍵部分的比較是一個範圍條件 =<=>IN()IS NULL,或IS NOT NULL運營商。
  • 另外,對於BTREE索引,當使用具有恆定值的關鍵部分的比較是一個範圍條件 ><>=<=BETWEEN!=,或 <>運營商,或者LIKE比較,如果引數 LIKE是一個常數字符串不與萬用字元開始。
  • 對於所有索引型別,多個範圍條件組合ORAND形成一個範圍條件。
前面的描述中的“ 恆定值 ”表示以下之一:
  • 查詢字串中的常量
  • 來自同一聯接 的const或[system表的 列
  • 不相關子查詢的結果
  • 任何完全由上述型別的子表示式組成的表示式
以下是該 WHERE 子句中具有範圍條件的查詢示例:
SELECT * FROM t1 WHERE key_col > 1 AND key_col < 10;SELECT * FROM t1 WHERE key_col = 1 OR key_col IN (15,18,20);SELECT * FROM t1 WHERE 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 如下:
  1. 從原始WHERE子句開始:
    (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR(key1 < 'bar' AND nonkey = 4) OR(key1 < 'uux' AND key1 > 'z')
  2. 刪除nonkey = 4key1 LIKE '%b'因為它們不能用於範圍掃描。刪除它們的正確方法是將它們替換為TRUE,這樣在進行範圍掃描時我們不會丟失任何匹配的行。用TRUE產量代替它們:
    (key1 < 'abc' AND (key1 LIKE 'abcde%' OR TRUE)) OR(key1 < 'bar' AND TRUE) OR(key1 < 'uux' AND key1 > 'z')
  3. 崩潰條件始終為true或false:用常量替換這些條件將產生:
    (key1 < 'abc' AND TRUE) OR (key1 < 'bar' AND TRUE) OR (FALSE)
    去除不必要的TRUEFALSE常數的產率:
    (key1 < 'abc') OR (key1 < 'bar')
  • (key1 LIKE 'abcde%' OR TRUE) 永遠是真的
  • (key1 < 'uux' AND key1 > 'z') 永遠是假的
將重疊的間隔合併為一個會產生用於範圍掃描的最終條件:
(key1 < 'bar')
一般而言(如前面的示例所示),範圍掃描所使用的條件比該 WHERE 子句的限制要少。MySQL執行附加檢查以過濾出滿足範圍條件但不包括full WHERE 子句的行。 範圍條件提取演算法可以處理 任意深度的巢狀 AND / OR 構造,並且其輸出不取決於條件在 WHERE 子句中出現的順序 。 MySQL不支援 range 為空間索引的訪問方法合併多個範圍 。要解決此限制,可以將a UNION 與相同的 SELECT 語句一起 使用,只是將每個空間謂詞放在不同的中 SELECT
多部分索引的範圍訪問方法
多部分索引的範圍條件是單部分索引的範圍條件的擴充套件。多部分索引上的範圍條件將索引行限制在一個或幾個鍵元組間隔內。使用從索引開始的順序,在一組鍵元組上定義鍵元組間隔。 例如,考慮定義為的多部分索引 ,並按鍵順序列出以下一組鍵元組: key1(* key_part1 *, * key_part2 *, * key_part3 *)
key_part1 key_part2 key_part3 NULL    1     'abc' NULL    1     'xyz' NULL    2     'foo'  1     1     'abc'  1     1     'xyz'  1     2     'abc'  2     1     'aaa'
條件 * key_part1 * = 1 定義了此間隔:
(1,-inf,-inf) <= (key_part1,key_part2,key_part3) < (1,+inf,+inf)
該間隔覆蓋了先前資料集中的第4,第5和第6個元組,並且可以由範圍訪問方法使用。 相反,該條件 * key_part3 * = 'abc' 未定義單個間隔,並且不能被範圍訪問方法使用。 以下描述更詳細地說明了範圍條件如何作用於多部分索引。
  • 對於HASH索引,可以使用包含相同值的每個間隔。這意味著只能針對以下形式的條件生成間隔:
       key_part1 cmp const1AND key_part2 cmp const2AND ...AND key_partN cmp constN;
    這裡const1const2...是常數,cmp是一個 =<=>或者IS NULL比較運營商,以及條件覆蓋所有指數部分。(也就是說,N 有條件,N-part索引的每個部分都有一個 條件。)例如,以下是三部分HASH索引的範圍條件 :
    key_part1 = 1 AND key_part2 IS NULL AND key_part3 = 'foo'
  • 對於一個BTREE索引,以一定間隔可能是可用於條件組合 AND,其中每個狀態具有恆定值使用一個關鍵部分進行比較 =, <=>, IS NULL, >, =, <=, !=, <>, BETWEEN,或 (其中 LIKE 'pattern''pattern' 不以萬用字元開頭)。只要可以確定包含所有與條件匹配的行的單個鍵元組,就可以使用一個間隔(如果使用<> 或,!= 則使用兩個間隔 )。只要比較運算子為,或=, 優化器就會嘗試使用其他關鍵部分來確定間隔 。如果操作是 , , , , , , ,或者 ,優化器使用它,但認為沒有更多的關鍵部分。對於以下表達式,優化器使用 第一個比較中的值。它也使用 <=>IS NULL><>=<=!=<>BETWEENLIKE=>= 根據第二次比較,但不考慮其他關鍵部分,並且不將第三次比較用於區間構造:
      key_part1 = 'foo' AND key_part2 >= 10 AND key_part3 > 10
  • 單個間隔為:
    ('foo',10,-inf) < (key_part1,key_part2,key_part3) < ('foo',+inf,+inf)
    建立的間隔可能包含比初始條件更多的行。例如,前面的時間間隔包含('foo', 11, 0)不滿足原始條件的值。
  • 如果將覆蓋間隔中包含的行集合的條件與組合OR,則它們將形成覆蓋間隔中的並 集中包含的行集合的條件。如果條件與組合 AND,則它們將形成一個條件,該條件覆蓋其間隔的交點內包含的一組行。例如,對於由兩部分組成的索引的這種情況:
    (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_lenEXPLAIN表示所使用的金鑰字首的最大長度。在某些情況下,key_len可能表明已使用了關鍵部件,但這可能不是您期望的。假設 key_part1key_part2可以是 NULL。然後,該 key_len列顯示以下條件的兩個關鍵零件長度:
    key_part1 >= 1 AND key_part2 < 2
    但是,實際上,條件已轉換為:
    key_part1 >= 1 AND key_part2 IS NOT NULL
多值比較的等距範圍優化
考慮以下表達式,其中 col_name 是索引列:
col_name IN(val1, ..., valN)col_name = val1 OR ... OR col_name = valN
如果 col_name 等於多個值中的任何一個,則每個表示式為true 。這些比較是相等範圍比較(其中“ range ”是單個值)。優化器估算相等範圍比較的讀取合格行的成本,如下所示:
  • 如果在上有唯一索引 col_name,則每個範圍的行估計為1,因為最多一行可以具有給定值。
  • 否則,任何索引 col_name都不是唯一的,優化器可以使用對索引或索引統計的深入估算來估計每個範圍的行數。
使用索引潛水時,優化器在範圍的每個末端進行潛水,並將範圍中的行數用作估計值。例如,表示式 * col_name * IN (10, 20, 30) 具有三個相等範圍,並且優化器對每個範圍進行兩次下潛以生成行估計。每對潛水都會得出具有給定值的行數的估計值。 索引潛水可提供準確的行估計,但是隨著表示式中比較值數量的增加,優化器將花費更長的時間來生成行估計。使用索引統計資料的準確性不及使用索引潛水的準確性,但允許對大型值列表進行更快的行估計。 使用 eq_range_index_dive_limit 系統變數,您可以配置優化程式從一種行估計策略切換到另一種行估計策略的值的數量。要允許使用索引潛水進行最多 N 等於範圍的比較,請設定 eq_range_index_dive_limitN +1。要禁用統計資訊,並且始終使用索引潛水而不管 N ,將其設定 eq_range_index_dive_limit 為0。 要更新表索引統計資訊以獲得最佳估計值,請使用 ANALYZE TABLE 。 即使在本應使用索引潛水的條件下,對於滿足所有這些條件的查詢也將跳過它們:
  • 存在單索引FORCE INDEX索引提示。這樣的想法是,如果強制使用索引,那麼執行潛入索引的額外開銷將無濟於事。
  • 索引不是唯一索引,不是 FULLTEXT索引。
  • 沒有子查詢。
  • 沒有DISTINCTGROUP BYORDER BY子句存在。
這些跳水條件僅適用於單表查詢。對於多表查詢(聯接),不會跳過索引潛水。
行建構函式表示式的範圍優化
優化器可以將範圍掃描訪問方法應用於以下形式的查詢:
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 值為):
    Warning   3170   Memory capacity of N bytes for          'range_optimizer_max_mem_size' exceeded. Range          optimization was not done for this query.
  • 對於UPDATE和 DELETE語句,如果優化器退回到全表掃描並且sql_safe_updates啟用了 系統變數,則會發生錯誤而不是警告,因為實際上,沒有鍵用於確定要修改的行
對於超出可用範圍優化記憶體的單個查詢,並且對於該查詢,優化器將退回至次優計劃,增加 range_optimizer_max_mem_size 值可以提高效能。 若要估計處理範圍表示式所需的記憶體量,請使用以下準則:
  • 對於諸如以下的簡單查詢,其中有一個用於範圍訪問方法的候選關鍵字,與組合OR 使用的每個謂詞大約使用230個位元組:
    SELECT COUNT(*) FROM tWHERE a=1 OR a=2 OR a=3 OR .. . a=N;
  • 類似地,對於以下查詢,每個謂詞組合AND使用大約125個位元組:
    SELECT COUNT(*) FROM tWHERE a=1 AND b=1 AND c=1 ... N;
  • 對於帶有IN()謂詞的查詢:
    SELECT COUNT(*) FROM tWHERE a IN (1,2, ..., M) AND b IN (1,2, ..., N);
    IN()列表 中的每個文字值都 與組合為謂詞OR。如果有兩個IN() 列表,則與組合的謂詞 OR數量是每個列表中文字值數量的乘積。因此,OR在前一種情況下組合的謂詞數 為 M× N。
往期好文

1.JVM 調優實戰

2.Spring Aop實戰案例二

3.程式設計師都在讀的書,你也不能錯過哦!

4.Java 8系列之重新認識HashMap

5.聊聊MyBatis二級快取機制

6.Map merge 你不知道的一波騷操作

7.Mysql執行計劃全解,SQL優化必備技能


小編寄語

小編建立了一個關於Java學習討論的微信群!想進去的可以聯絡小編!同時也歡迎大家點贊與轉發!

小編微信:372787553

備註為進群,通過後小編會邀請您進群!

Ja va有貨因您而美 e223b928e24c94fc2a1ca753734798f7.gif