簡體   English   中英

MySQL 5.7.36 Where 子句 OR 運算符不短路

[英]MySQL 5.7.36 Where Clause OR Operator not Short Circuiting

我搜索了所有紫色的 Google 鏈接,但沒有找到解決問題的方法。

據我所知,MySQL 不會在where子句中短路OR運算符。 很多搜索結果解釋了為什么會發生這種情況,但這實際上並不能幫助解決我的問題。

我們正在運行 MySQL 版本5.7.36

以下是查詢中性能差異的結果:

使用 OR 子句查詢( 2 s 761 ms ):

select count(*) from account_transaction
       where (true or description like '%')
         and datetime between '2022-05-19 00:00:00' and '2022-05-26 00:00:00'
[2022-05-27 08:28:36] 1 row retrieved starting from 1 in 2 s 787 ms (execution: 2 s 761 ms, fetching: 26 ms)

執行計划:

mysql> explain select count(*) from account_transaction
    ->        where (true or description like '%')
    ->          and datetime between '2022-05-19 00:00:00' and '2022-05-26 00:00:00';
+----+-------------+---------------------+------------+------+----------------------------------+------+---------+------+---------+----------+-------------+
| id | select_type | table               | partitions | type | possible_keys                    | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+---------------------+------------+------+----------------------------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | account_transaction | NULL       | ALL  | account_transaction_datetime_idx | NULL | NULL    | NULL | 1172455 |    19.69 | Using where |
+----+-------------+---------------------+------------+------+----------------------------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.03 sec)

不帶 OR 子句的查詢( 267ms ):

select count(*) from account_transaction
       where (true)
         and datetime between '2022-05-19 00:00:00' and '2022-05-26 00:00:00'
[2022-05-27 08:26:09] 1 row retrieved starting from 1 in 286 ms (execution: 267 ms, fetching: 19 ms)

執行計划:

mysql> explain select count(*) from account_transaction
    ->        where (true)
    ->          and datetime between '2022-05-19 00:00:00' and '2022-05-26 00:00:00';
+----+-------------+---------------------+------------+-------+----------------------------------+----------------------------------+---------+------+--------+----------+--------------------------+
| id | select_type | table               | partitions | type  | possible_keys                    | key                              | key_len | ref  | rows   | filtered | Extra                    |
+----+-------------+---------------------+------------+-------+----------------------------------+----------------------------------+---------+------+--------+----------+--------------------------+
|  1 | SIMPLE      | account_transaction | NULL       | range | account_transaction_datetime_idx | account_transaction_datetime_idx | 6       | NULL | 230898 |   100.00 | Using where; Using index |
+----+-------------+---------------------+------------+-------+----------------------------------+----------------------------------+---------+------+--------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

這個查詢是由 Spring JPA 生成的,因此沒有方便的方法來自己生成查詢。

嘗試添加另一個索引,但執行計划保持不變:

create index account_transaction__indextest
    on account_transaction (description asc, datetime desc);

帶有附加索引的執行計划:

mysql> explain select * from account_transaction
    -> where (true or description like '%')
    ->   and datetime between '2022-05-19 00:00:00' and '2022-05-26 00:00:00'
    -> ;
+----+-------------+---------------------+------------+------+----------------------------------+------+---------+------+------+----------+-------------+
| id | select_type | table               | partitions | type | possible_keys                    | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------------------+------------+------+----------------------------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | account_transaction | NULL       | ALL  | account_transaction_datetime_idx | NULL | NULL    | NULL |  160 |    80.62 | Using where |
+----+-------------+---------------------+------------+------+----------------------------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
  • 請提供SHOW CREATE TABLE以便我們了解數據類型、索引等。
  • 計時查詢時,請運行兩次。 由於加載緩存,第一個可能很慢; 因此第二個可能更快。
  • 優化器會查看一些粗略的統計數據來決定哪個索引最有用,或者沒有索引值得費心。 從這個角度分析您的查詢,您從查詢中得到了多少? 表格中有多少行?
  • 第二個EXPLAIN似乎暗示某些索引以datetime開頭。
  • 我更喜歡構建沒有諸如true11=1... LIKE '%'類的查詢。 它使優化器的工作更加困難。 顯然它分散了它“做正確的事”的注意力。
  • “Using where”可能表示它正在檢查description LIKE '%' 如果是這樣,您可以編寫一個錯誤報告來建議將其優化為 TRUE。 但它可能會被拒絕,因為這實際上可能被視為description IS NOT NULL 運行SHOW WARNINGS; 執行EXPLAIN后。
  • Extras 中缺少“使用索引”表明它必須進入數據的 BTree。 也就是說,要么沒有索引“覆蓋”,要么優化器出於其他原因選擇掃描表。
  • 'Apples and oranges' - SELECT *EXPLAINs和時間通常與SELECT COUNT(*)完全不同。 選擇你想討論的; 不要混合它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM