MySQL使用LIKE索引是否失效的驗證

1、簡單的示例展示

在MySQL中,LIKE查詢可以通過一些方法來使得LIKE查詢能夠使用索引。以下是一些可以使用的方法:

  • 使用前導通配符(%),但確保它緊跟著一個固定的字符。

  • 避免使用后置通配符(%),只在查詢的末尾使用。

  • 使用COLLATE來控制字符串比較的行為,使得查詢能夠使用索引。

下面是一個簡單的例子,演示如何使用LIKE查詢并且使索引有效

-- 假設我們有一個表 users,有一個索引在 name 字段上
CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(255)
);-- 創建索引
CREATE INDEX idx_name ON users(name);-- 使用 LIKE 查詢,并且利用索引進行查詢的例子
-- 使用前導通配符,確保它緊跟著一個固定的字符
SELECT * FROM users WHERE name LIKE 'A%'; -- 使用索引-- 避免使用后置通配符
SELECT * FROM users WHERE name LIKE '%A'; -- 不使用索引-- 使用 COLLATE 來確保比較符合特定的語言或字符集規則
SELECT * FROM users WHERE name COLLATE utf8mb4_unicode_ci LIKE '%A%'; -- 使用索引

在實際應用中,你需要根據你的數據庫表結構、查詢模式和數據分布來決定是否可以使用LIKE查詢并且使索引有效。如果LIKE查詢不能使用索引,可以考慮使用全文搜索功能或者其他查詢優化技巧。

2、實驗演示是否能正確使用索引

2.1、表及數據準備

準備兩張表 t_departments 和 t_deptlist

(root@192.168.80.85)[superdb]> desc t_departments;
+-----------------+-------------+------+-----+---------+-------+
| Field           | Type        | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| DEPARTMENT_ID   | int         | NO   | PRI | NULL    |       |
| DEPARTMENT_NAME | varchar(30) | YES  |     | NULL    |       |
| MANAGER_ID      | int         | YES  |     | NULL    |       |
| LOCATION_ID     | int         | YES  | MUL | NULL    |       |
+-----------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)(root@192.168.80.85)[superdb]> create table t_deptlist as select DEPARTMENT_ID,DEPARTMENT_NAME from t_departments;
Query OK, 29 rows affected (0.09 sec)
Records: 29  Duplicates: 0  Warnings: 0(root@192.168.80.85)[superdb]> desc t_deptlist;
+-----------------+-------------+------+-----+---------+-------+
| Field           | Type        | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| DEPARTMENT_ID   | int         | NO   |     | NULL    |       |
| DEPARTMENT_NAME | varchar(30) | YES  |     | NULL    |       |
+-----------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)(root@192.168.80.85)[superdb]> alter table t_deptlist add constraint pk_t_deptlist_id primary key(DEPARTMENT_ID);
Query OK, 0 rows affected (0.13 sec)
Records: 0  Duplicates: 0  Warnings: 0(root@192.168.80.85)[superdb]> create index idx_t_deptlist_department_name on t_deptlist(department_name);
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0(root@192.168.80.85)[superdb]> show index from t_departments;
+---------------+------------+-----------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table         | Non_unique | Key_name              | Seq_in_index | Column_name     | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+---------------+------------+-----------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| t_departments |          0 | PRIMARY               |            1 | DEPARTMENT_ID   | A         |          29 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| t_departments |          1 | idx_t_department_name |            1 | DEPARTMENT_NAME | A         |          29 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+---------------+------------+-----------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.00 sec)(root@192.168.80.85)[superdb]> show index from t_deptlist;
+------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table      | Non_unique | Key_name                       | Seq_in_index | Column_name     | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| t_deptlist |          0 | PRIMARY                        |            1 | DEPARTMENT_ID   | A         |          29 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| t_deptlist |          1 | idx_t_deptlist_department_name |            1 | DEPARTMENT_NAME | A         |          29 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.00 sec)

表t_departments有多個字段列,其中DEPARTMENT_ID是主鍵,DEPARTMENT_NAME是索引字段,其它是非索引字段列

表t_deptlist有兩個字段,其中DEPARTMENT_ID是主鍵,DEPARTMENT_NAME是索引字段

2.2、 執行 where DEPARTMENT_NAME LIKE ‘Sales’


(root@192.168.80.85)[superdb]> explain select * from t_departments where DEPARTMENT_NAME LIKE 'Sales';
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
| id | select_type | table         | partitions | type  | possible_keys         | key                   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | t_departments | NULL       | range | idx_t_department_name | idx_t_department_name | 123     | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)(root@192.168.80.85)[superdb]> explain select * from t_deptlist where DEPARTMENT_NAME LIKE 'Sales';
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys                  | key                            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t_deptlist | NULL       | range | idx_t_deptlist_department_name | idx_t_deptlist_department_name | 123     | NULL |    1 |   100.00 | Using where; Using index |
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.01 sec)

執行計劃查看,發現選擇掃描二級索引index_name,表t_departments有多個字段列的行計劃中的 Extra=Using index condition 使用了索引下推功能。MySQL5.6 之后,增加一個索引下推功能,可以在索引遍歷過程中,對索引中包含的字段先做判斷,在存儲引擎層直接過濾掉不滿足條件的記錄后再返回給 MySQL Server 層,減少回表次數,從而提升了性能。

2.3、 執行 where DEPARTMENT_NAME LIKE ‘Sa%’

(root@192.168.80.85)[superdb]> explain select * from t_departments where DEPARTMENT_NAME LIKE 'Sa%';
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+-------------+------+------+----------+-----------------------+
| id | select_type | table         | partitions | type  | possible_keys         | key                   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+-------------+------+------+----------+-----------------------+
|  1 | SIMPLE      | t_departments | NULL       | range | idx_t_department_name | idx_t_department_name | 123     | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)(root@192.168.80.85)[superdb]> explain select * from t_deptlist where DEPARTMENT_NAME LIKE 'Sa%';
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys                  | key                            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t_deptlist | NULL       | range | idx_t_deptlist_department_name | idx_t_deptlist_department_name | 123     | NULL |    1 |   100.00 | Using where; Using index |
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

執行計劃查看,發現選擇掃描二級索引index_name

2.4、 執行 where DEPARTMENT_NAME LIKE ‘%ale%’

(root@192.168.80.85)[superdb]> explain select * from t_departments where DEPARTMENT_NAME LIKE '%ale%';
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table         | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_departments | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   29 |    11.11 | Using where |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)(root@192.168.80.85)[superdb]> explain select * from t_deptlist where DEPARTMENT_NAME LIKE '%ale%';
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys | key                            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t_deptlist | NULL       | index | NULL          | idx_t_deptlist_department_name | 123     | NULL |   29 |    11.11 | Using where; Using index |
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

表t_departments有多個字段列的執行計劃的結果 type= ALL,代表了全表掃描。
表t_deptlist 有兩個字段列的執行計劃的結果中,可以看到 key=idx_t_deptlist_department_name ,也就是說用上了二級索引,而且從 Extra 里的 Using index 說明用上了覆蓋索引。

2.5、 執行 where DEPARTMENT_NAME LIKE ‘%ale’

(root@192.168.80.85)[superdb]> explain select * from t_departments where DEPARTMENT_NAME LIKE '%ale';
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table         | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_departments | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   29 |    11.11 | Using where |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)(root@192.168.80.85)[superdb]> explain select * from t_deptlist where DEPARTMENT_NAME LIKE '%ale';
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys | key                            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t_deptlist | NULL       | index | NULL          | idx_t_deptlist_department_name | 123     | NULL |   29 |    11.11 | Using where; Using index |
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

表t_departments有多個字段列的執行計劃的結果 type= ALL,代表了全表掃描。
表t_deptlist 有兩個字段列的執行計劃的結果中,可以看到 key=idx_t_deptlist_department_name ,也就是說用上了二級索引,而且從 Extra 里的 Using index 說明用上了覆蓋索引。
和上一個LIKE ‘%ale%’ 一樣的結果。

3、為什么表t_deptlist where department_name LIKE ‘%ale’ 和 LIKE '%ale%'用上了二級索引

首先,這張表的字段沒有「非索引」字段,所以 SELECT * 相當于 SELECT DEPARTMENT_ID,DEPARTMENT_NAME,這個查詢的數據都在二級索引的 B+ 樹,因為二級索引idx_t_deptlist_department_name 的 B+ 樹的葉子節點包含「索引值+主鍵值」,所以查二級索引的 B+ 樹就能查到全部結果了,這個就是覆蓋索引。

從執行計劃里的 type 是 index,這代表著是通過全掃描二級索引的 B+ 樹的方式查詢到數據的,也就是遍歷了整顆索引樹。

而 LIKE 'Sales’和LIKE 'Sa%'查詢語句的執行計劃中 type 是 range,表示對索引列DEPARTMENT_NAME進行范圍查詢,也就是利用了索引樹的有序性的特點,通過查詢比較的方式,快速定位到了數據行。

所以,type=range 的查詢效率會比 type=index 的高一些。

4、為什么選擇全掃描二級索引樹,而不掃描聚簇索引樹呢?

因為表t_deptlist 二級索引idx_t_deptlist_department_name 的記錄是「索引列+主鍵值」,而聚簇索引記錄的東西會更多,比如聚簇索引中的葉子節點則記錄了主鍵值、事務 id、用于事務和 MVCC 的回滾指針以及所有的非索引列。

再加上表t_deptlist 只有兩個字段列,DEPARTMENT_ID是主鍵,DEPARTMENT_NAME是索引字段,因此 SELECT * 相當于 SELECT DEPARTMENT_ID,DEPARTMENT_NAME 不用執行回表操作。

所以, MySQL 優化器認為直接遍歷二級索引樹要比遍歷聚簇索引樹的成本要小的多,因此 MySQL 優化器選擇了「全掃描二級索引樹」的方式查詢數據。

5、數據表t_departments 多了非索引字段,執行同樣的查詢語句,為什么是全表掃描呢?

多了其他非索引字段后,select * from t_departments where DEPARTMENT_NAME LIKE ‘%ale’ OR DEPARTMENT_NAME LIKE ‘%ale%’ ; 要查詢的數據就不能只在二級索引樹里找了,得需要回表操作找到主鍵值才能完成查詢的工作,再加上是左模糊匹配,無法利用索引樹的有序性來快速定位數據,所以得在二級索引樹逐一遍歷,獲取主鍵值后,再到聚簇索引樹檢索到對應的數據行,這樣執行成本就會高了。

所以,優化器認為上面這樣的查詢過程的成本實在太高了,所以直接選擇全表掃描的方式來查詢數據。

如果數據庫表中的字段只有主鍵+二級索引,那么即使使用了左模糊匹配或左右模糊匹配,也不會走全表掃描(type=all),而是走全掃描二級索引樹(type=index)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/41981.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/41981.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/41981.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【致知功夫 各隨分限】成長需要時間,助人須考慮對方的承受程度

幫助他人需考慮各人的分限所能及的,初學圣學需時間沉淀,存養心性 任何人都應該受到教育,不應受到貧富、貴賤的差異而排除在教育之外,對于不同材質的學生,需要因材施教; 每天都有新的認知,大我…

STL—容器—string類【對其結構和使用的了解】【對oj相關練習的訓練】

STL—容器—string類 其實string類準確來說并不是容器,因為他出現的時間比STL要早,但是也可以說是容器吧。 1.為什么要學習string類? 1.1C語言當中的字符串 C語言中,字符串是以’\0’結尾的一些字符的集合,為了操作…

CTFShow的RE題(三)

數學不及格 strtol 函數 long strtol(char str, char **endptr, int base); 將字符串轉換為長整型 就是解這個方程組了 主要就是 v4, v9的關系, 3v9-(v10v11v12)62d10d4673 v4 v12 v11 v10 0x13A31412F8C 得到 3*v9v419D024E75FF(1773860189695) 重點&…

Windows ipconfig命令詳解,Windows查看IP地址信息

「作者簡介」:冬奧會網絡安全中國代表隊,CSDN Top100,就職奇安信多年,以實戰工作為基礎著作 《網絡安全自學教程》,適合基礎薄弱的同學系統化的學習網絡安全,用最短的時間掌握最核心的技術。 ipconfig 1、基…

Android Studio Run窗口中文亂碼解決辦法

Android Studio Run窗口中文亂碼解決辦法 問題描述: AndroidStudio 編譯項目時Run窗口中文亂碼,如圖: 解決方法: 依次打開菜單:Help--Edit Custom VM Options,打開studio64.exe.vmoptions編輯框&#xf…

計算機專業怎么選擇電腦

現在高考錄取結果基本已經全部出來了,很多同學都如愿以償的進入到了計算機類專業,現在大部分同學都在為自己的大學生活做準備了,其中第一件事就是買電腦,那計算機類專業該怎么選擇電腦呢? 計算機專業是個一類學科&…

網絡中的網絡 NiN

一、全連接層問題 1、卷積層的參數:輸入的通道數乘以輸出的通道數再乘以窗口的高寬 2、全連接層的參數就是輸入的元素個數乘以輸出的元素個數,也就是輸入的通道數乘以輸入的高寬,再乘以輸出的通道數乘以輸出的高寬,賊大的量級 …

NLP簡介

自然語言處理( Natural Language Processing, NLP)是計算機科學領域與人工智能領域中的一個重要方向。它研究能實現人與計算機之間用自然語言進行有效通信的各種理論和方法。自然語言處理是一門融語言學、計算機科學、數學于一體的科學。因此,這一領域的研究將涉及自…

【算法】(C語言):冒泡排序、選擇排序、插入排序

冒泡排序 從第一個數據開始到第n-1個數據,依次和后面一個數據兩兩比較,數值小的在前。最終,最后一個數據(第n個數據)為最大值。從第一個數據開始到第n-2個數據,依次和后面一個數據兩兩比較,數值…

關于用戶咨詢華為擎云L410筆記本安裝Windows系統的說明

同樣也是單位購買的華為擎云L410 KLVU-WDU0筆記本電腦,國產UOS系統某些軟件用著不是很方便,用戶咨詢是否能夠安裝Windows10或者Windows7? 帶著種種疑問也做了一些查詢,之前也給一些國產設備更改過操作系統,之前的國產設…

計算機網絡淺談—什么是 OSI 模型?

開放系統通信(OSI)模型是一個代表網絡通信工作方式的概念模型。 思維導圖 什么是 OSI 模型? 開放系統互連 (OSI) 模型是由國際標準化組織創建的概念模型,支持各種通信系統使用標準協議進行通信。簡單而言,OSI 為保證…

智能交通(3)——Learning Phase Competition for Traffic Signal Control

論文分享 https://dl.acm.org/doi/pdf/10.1145/3357384.3357900https://dl.acm.org/doi/pdf/10.1145/3357384.3357900 論文代碼 https://github.com/gjzheng93/frap-pubhttps://github.com/gjzheng93/frap-pub 摘要 越來越多可用的城市數據和先進的學習技術使人們能夠提…

Laravel框架詳解及使用方法

Laravel是一款開源的PHP Web應用程序框架,它基于MVC(模型-視圖-控制器)架構,以其簡單易學、靈活性強、安全性高和強大的社區支持而廣受開發者喜愛。以下是對Laravel框架的詳細解析及使用方法: 一、Laravel框架簡介 1…

刷題——在二叉樹中找到最近公共祖先

在二叉樹中找到兩個節點的最近公共祖先_牛客題霸_牛客網 int lowestCommonAncestor(TreeNode* root, int o1, int o2) {if(root NULL) return -1;if((root->val o1) || (root->val o2)) return root->val;int left lowestCommonAncestor(root->left, o1, o2);i…

【pytorch19】交叉熵

分類問題的loss MSECross Entropy LossHinge Loss (SVN用的比較多) ∑ i m a x ( 0 , 1 ? y i ? h θ ( x i ) ) \sum_imax(0,1-y_i*h_\theta(x_i)) ∑i?max(0,1?yi??hθ?(xi?)) Entropy(熵) Uncertainty(…

ESP32——物聯網小項目匯總

商品級ESP32智能手表 [文章鏈接] 用ESP32,做了個siri?!開源了! [文章鏈接]

IPsec連接 和 SSL連接

Psec和SSL連接是兩種用于保障網絡通信安全的技術 IPsec 通常用于連通兩個局域網,主要是網對網的連接,如分支機構與總部之間,或者本地IDC與云端VPC的子網連接。適合站點間的穩定通訊需求以及對網絡層安全有嚴格要求的場合。要求兩端有固定的網…

UDP協議:獨特之處及其在網絡通信中的應用

在網絡通信領域,UDP(用戶數據報協議,User Datagram Protocol)是一種廣泛使用的傳輸層協議。與TCP(傳輸控制協議,Transmission Control Protocol)相比,UDP具有其獨特的特點和適用場景…

對數據采集、數據存儲和數據處理流程

對數據采集、數據存儲和數據處理流程 數據采集是指從各種來源收集原始數據的過程,這通常包括傳感器、網站、社交媒體、API等。它涉及設置抓取工具、爬蟲技術或直接從數據庫獲取數據。數據存儲則涉及到將采集到的數據安全、高效地保存起來,常見的有關系型…

EDEM-FLUENT耦合報錯幾大原因總結(持續更新)

寫在前面,本篇內容主要是來源于自己做仿真時的個人總結,以及付費請教專業老師。每個人由于工況不一樣,所以報錯原因千奇百怪,不能一概而論,本篇內容主要是為本專欄讀者在報錯時提供大致的糾錯方向,從而達到少走彎路的效果,debug的過程需要大家一點點試算。問題解答在文 …