mysql5.7關於使用到OR是否會用到索引並提高查詢效率的探討

来源:https://www.cnblogs.com/soysauce/archive/2019/03/01/10414296.html
-Advertisement-
Play Games

相信很多人在mysql中看到了where條件中使用到了or就會以為這樣是不會走索引的,通常會使用union all或者in 來進行優化,事實並不是想象的這樣具體問題具體分析。 下麵我們來看看 首先我們用sysbench生成兩個100w行的表 表結構如下 1.首先我們使用同一列帶索引欄位的進行查詢。 ...


相信很多人在mysql中看到了where條件中使用到了or就會以為這樣是不會走索引的,通常會使用union all或者in 來進行優化,事實並不是想象的這樣具體問題具體分析。

下麵我們來看看

首先我們用sysbench生成兩個100w行的表

表結構如下

mysql> show create table sbtest1 \G;
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`),
  KEY `c_1` (`c`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

ERROR: 
No query specified

mysql> show create table sbtest2 \G;
*************************** 1. row ***************************
       Table: sbtest2
Create Table: CREATE TABLE `sbtest2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_2` (`k`),
  KEY `c_2` (`c`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

ERROR: 
No query specified

1.首先我們使用同一列帶索引欄位的進行查詢。

mysql> explain select * from sbtest1 where k='501462' or k='502480';   
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | sbtest1 | NULL       | range | k_1           | k_1  | 4       | NULL |  214 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+

從執行計劃中看出這樣是可以使用到索引的,另外我們使用in 或者union all來看。

mysql> explain select pad from sbtest1 where k in ('501462','502480');
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | sbtest1 | NULL       | range | k_1           | k_1  | 4       | NULL |  214 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+

in的執行計劃和or相同。

mysql>  explain select pad from sbtest1 where k='501462' union all select pad from sbtest1 where k='502480';
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | PRIMARY     | sbtest1 | NULL       | ref  | k_1           | k_1  | 4       | const |  113 |   100.00 | NULL  |
|  2 | UNION       | sbtest1 | NULL       | ref  | k_1           | k_1  | 4       | const |  101 |   100.00 | NULL  |

雖然執行計劃不通但union all估計的查詢行數和上面相同。

2.我們再來看看不同列帶索引欄位的進行查詢

mysql> explain select pad from sbtest1 where  k='501462' or c='68487932199-96439406143-93774651418-41631865787-96406072701-20604855487-25459966574-28203206787-41238978918-19503783441';
+----+-------------+---------+------------+-------------+---------------+---------+---------+------+------+----------+-----------------------------------+
| id | select_type | table   | partitions | type        | possible_keys | key     | key_len | ref  | rows | filtered | Extra                             |
+----+-------------+---------+------------+-------------+---------------+---------+---------+------+------+----------+-----------------------------------+
|  1 | SIMPLE      | sbtest1 | NULL       | index_merge | k_1,c_1       | k_1,c_1 | 4,120   | NULL |  114 |   100.00 | Using union(k_1,c_1); Using where |
+----+-------------+---------+------------+-------------+---------------+---------+---------+------+------+----------+-----------------------------------

這樣的情況也會使用索引

如果or的條件中有個條件不帶索引的話,那這條sql就不會使用到索引了,如下。

mysql> explain select pad from sbtest1 where  k='501462' or pad='00592560354-80393027097-78244247549-39135306455-88936868384';
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | sbtest1 | NULL       | ALL  | k_1           | NULL | NULL    | NULL | 986400 |    19.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+

pad列沒索引所以整條的sql就不會使用到索引

假設使用union all來改寫一樣需要全表掃描所以意義也不大,如下

mysql>  explain select pad from sbtest1 where  k='501462' union all select pad from sbtest1 where pad='00592560354-80393027097-78244247549-39135306455-88936868384';
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref   | rows   | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
|  1 | PRIMARY     | sbtest1 | NULL       | ref  | k_1           | k_1  | 4       | const |    113 |   100.00 | NULL        |
|  2 | UNION       | sbtest1 | NULL       | ALL  | NULL          | NULL | NULL    | NULL  | 986400 |    10.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+

3.接下來我們看看多表關聯查詢

 

mysql> explain select a.pad,b.pad from sbtest1 a,sbtest2 b where a.id=b.id and (a.c='123' or b.c='1234');                 
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+--------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref       | rows   | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+--------+----------+-------------+
|  1 | SIMPLE      | a     | NULL       | ALL    | PRIMARY,c_1   | NULL    | NULL    | NULL      | 986400 |   100.00 | NULL        |
|  1 | SIMPLE      | b     | NULL       | eq_ref | PRIMARY,c_2   | PRIMARY | 4       | test.a.id |      1 |   100.00 | Using where |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+--------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

mysql> explain select a.pad,b.pad from sbtest1 a,sbtest2 b where a.id=b.id and (a.c='123' or a.c='1234'); 
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-----------------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref       | rows | filtered | Extra                 |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-----------------------+
|  1 | SIMPLE      | a     | NULL       | range  | PRIMARY,c_1   | c_1     | 120     | NULL      |    2 |   100.00 | Using index condition |
|  1 | SIMPLE      | b     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.a.id |    1 |   100.00 | NULL                  |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-----------------------+
2 rows in set, 1 warning (0.00 sec)

mysql> 

可以看出在多表查詢的情況下or條件如果不在同一個表內執行計劃表a的查詢不走索引。

我們試試看用union all來進行改寫

mysql> explain select a.pad,a.c from sbtest1 a,sbtest2 b where a.id=b.id and a.c='123' union all select a.pad,a.c from sbtest1 a,sbtest2 b where a.id=b.id and b.c='1234';
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref       | rows | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------------+
|  1 | PRIMARY     | a     | NULL       | ref    | PRIMARY,c_1   | c_1     | 120     | const     |    1 |   100.00 | NULL        |
|  1 | PRIMARY     | b     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.a.id |    1 |   100.00 | Using index |
|  2 | UNION       | b     | NULL       | ref    | PRIMARY,c_2   | c_2     | 120     | const     |    1 |   100.00 | Using index |
|  2 | UNION       | a     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.b.id |    1 |   100.00 | NULL        |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------------+

在or的條件不在同一個表的情況下 使用union all來改寫掃描行數減少且會走索引。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.在啟動的時候按住方向鍵停留在內核選項頁面,在內核選項出按e鍵 2.進入到另一個頁面後,尋找到以linux16開頭的地方,按end到行後,輸入空格,然後輸入rd.break console=tty0,並按ctrl+x組合鍵進入到GRUB引導頁面 3.進入之後,輸入掛載命令改變根分區的掛載選項,命令 ...
  • 使用命令: 說明:user 為當前用戶; 完畢! ...
  • 1.在Linux系統中的【 ~/.baserc 】文件與【 /etc/profile 】配置環境變數後(可以使任意環境變數)無效的現象,如下為解決辦法: 使用命令: 在 【# User configuration】下添加環境變數; 如圖說明: 2.也可以直接將【 ~/.baserc 】文件或【 /e ...
  • 0x00 ubuntu server 16.04 開啟root密碼登錄由於眾多VPS預設使用證書驗證登錄,雖然安全但使用十分不便,所以特提供開啟root用戶並使用密碼登錄方法。0x01 為root賬戶設置密碼$ sudo passwd root0x02 進入root賬戶$ su root0x03 編... ...
  • 簡介 介紹 Docker的存儲捲稱之為volume,本質上容器上的一個或者多個目錄,而這些目錄繞過了聯合文件系統,與宿主機中的目錄或者其他容器目錄進行了綁定關係,這種綁定關係可以看作Linux的mount操作,當容器中的程式對這些目錄寫入數據時,其實寫入到的是與之綁定的宿主機目錄上,這樣就實現了數據 ...
  • 1、下載python3 2、解壓 先建一個編譯目錄: Python3.7版本需要一個新的依賴包libffi-devel,安裝此包之後再次進行編譯安裝即可。 然後編譯、安裝: 建立軟鏈接: 查看版本: 安裝結束! ...
  • 筆記記錄自林曉斌(丁奇)老師的《MySQL實戰45講》 6) --全局鎖和表鎖:給表加個欄位怎麼有這麼多阻礙 資料庫鎖設計的初衷是處理併發問題。作為多用戶共用的資源,當出現併發訪問的時候,資料庫需要合理地控制資源的訪問規則。而鎖就是用來實現這些訪問規則的重要結構。根據加鎖的範圍,MySQL裡面的鎖大 ...
  • 通過phpmyadmin ,創建procedure, 用於生成測試數據。 隨機的用戶名及手機號。 調用: call sp_insert_test_users(10); ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...