mysql 查询重写_mysql 学习 - 查询重写规则
條件化簡
我們編寫的查詢語句的搜索條件本質上是一個表達式,這些表達式可能比較繁雜,或者不能高效的執行,MySQL的查詢優化器會為我們簡化這些表達式。
移除不必要的括號
有時候表達式里有許多無用的括號,比如這樣:
((a = 5 AND b = c) OR ((a > c) AND (c < 5)))
看著就很煩,優化器會把那些用不到的括號給干掉,就是這樣:
(a = 5 and b = c) OR (a > c AND c < 5)
常量傳遞(constant_propagation)
有時候某個表達式是某個列和某個常量做等值匹配,比如這樣:
a = 5
當這個表達式和其他涉及列a的表達式使用AND連接起來時,可以將其他表達式中的a的值替換為5,比如這樣:
a = 5 AND b > a
就可以被轉換為:
a = 5 AND b > 5
移除沒用的條件(trivial_condition_removal)
對于一些明顯永遠為TRUE或者FALSE的表達式,優化器會移除掉它們,比如這個表達式:
(a < 1 and b = b) OR (a = 6 OR 5 != 5)
優化后為:
a < 1 OR a = 6
外連接消除
內連接的驅動表和被驅動表的位置可以相互轉換,而左(外)連接和右(外)連接的驅動表和被驅動表是固定的。這就導致內連接可能通過優化表的連接順序來降低整體的查詢成本,而外連接卻無法優化表的連接順序。
如果能夠將外連接轉換為內連接, 則 mysql 的查詢優化器就可以使用內連接的一些優化措施進行優化. 我們了解一下什么情況下外連接的查詢語句可以轉換成為內連接.比如下面的 sql 語句:
SELECT * FROM t1 LEFT JOIN t2 ON t1.m1 = t2.m2 WHERE t2.n2 IS NOT NULL;
在這種情況下:外連接和內連接也就沒有什么區別了. 當然,我們也可以不用顯式的指定被驅動表的某個列IS NOT NULL,只要隱含的有這個意思就行了,比方說這樣:
SELECT * FROM t1 LEFT JOIN t2 ON t1.m1 = t2.m2 WHERE t2.m2 = 2;
所以上邊的這個左(外)連接查詢其實和下邊這個內連接查詢是等價的:
SELECT * FROM t1 INNER JOIN t2 ON t1.m1 = t2.m2 WHERE t2.m2 = 2;
我們把這種在外連接查詢中,指定的WHERE子句中包含被驅動表中的列不為NULL值的條件稱之為空值拒絕(英文名:reject-NULL)。在被驅動表的WHERE子句符合空值拒絕的條件后,外連接和內連接可以相互轉換。這種轉換帶來的好處就是查詢優化器可以通過評估表的不同連接順序的成本,選出成本最低的那種連接順序來執行查詢。
子查詢優化
子查詢分為:
標量子查詢
行子查詢
列子查詢
表子查詢
按與外層查詢關系來區分子查詢:
不相關子查詢
相關子查詢
子查詢語法注意事項
子查詢必須用小括號擴起來。
在SELECT子句中的子查詢必須是標量子查詢。
在想要得到標量子查詢或者行子查詢,但又不能保證子查詢的結果集只有一條記錄時,應該使用LIMIT 1語句來限制記錄數量。
對于[NOT] IN/ANY/SOME/ALL子查詢來說,子查詢中不允許有LIMIT語句。
子查詢的結果其實就相當于一個集合,集合里的值排不排序一點兒都不重要,比如下邊這個語句中的ORDER BY子句簡直就是畫蛇添足
集合里的值去不去重也沒啥意義
不允許在一條語句中增刪改某個表的記錄時同時還對該表進行子查詢
IN子查詢優化
對于不相關的IN子查詢,比如這樣:
SELECT * FROM s1 WHERE key1 IN (SELECT common_field FROM s2 WHERE key3 = 'a');
不直接將不相關子查詢的結果集當作外層查詢的參數,而是將該結果集寫入一個臨時表里。
該臨時表的列就是子查詢結果集中的列。
寫入臨時表的記錄會被去重。
一般情況下子查詢結果集不會大的離譜,所以會為它建立基于內存的使用Memory存儲引擎的臨時表,而且會為該表建立哈希索引。(如果子查詢的結果集非常大,超過了系統變量tmp_table_size或者max_heap_table_size,臨時表會轉而使用基于磁盤的存儲引擎來保存結果集中的記錄,索引類型也對應轉變為B+樹索引。)
當我們把子查詢進行物化之后,假設子查詢物化表的名稱為materialized_table,該物化表存儲的子查詢結果集的列為m_val, 也就是說其實上邊的查詢就相當于表s1和子查詢物化表materialized_table進行內連接:
SELECT s1.* FROM s1 INNER JOIN materialized_table ON key1 = m_val;
能不能不進行物化操作直接把子查詢轉換為連接呢?大家有興趣可以了解了解semi-join
總結
以上是生活随笔為你收集整理的mysql 查询重写_mysql 学习 - 查询重写规则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rtti是什么java_RTTI
- 下一篇: mysql的复合类型_PLSQL 复合类