mysql索引優化實際例子_MySQL索引優化的實際案例分析

Order by desc/asc limit M是我在mysql sql優化中經常遇到的一種場景,其優化原理也非常的簡單,就是利用索引的有序性,優化器沿著索引的順序掃描,在掃描到符合條件的M行數據后,停止掃描;看起來非常的簡單,但是我經常看到很多性能較差的sql沒有利用這個優化規律,下面將結合一些實際的案例來分析說明:

案例一:

一條sql執行非常的慢,執行時間為:

root@test 02:00:44

SELECT * FROM test_order_desc WHERE END_TIME>now() ORDER BY GMT_CREATE DESC,count_num DESC LIMIT 12, 12;

+---------+-----------+------------+------+---------------------+---------------------+-------------------

Data1.....................................................................................................

Data2.....................................................................................................

+---------+-----------+------------+------+---------------------+---------------------+-------------------

12 ROWS IN SET (0.49 sec)

執行計劃如下:

root@test_db01:53:23

EXPLAIN SELECT * FROM test_order_desc WHERE END_TIME > now()

ORDER BY GMT_CREATE DESC,count_num DESC LIMIT 12, 12;

+----+-------------+----------+-------+-----------------+-----------------+---------+------+--------+-----

| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | REF | ROWS | Extra |

+----+-------------+----------+-------+-----------------+-----------------+---------+------+--------+-----

| 1 | SIMPLE | test_order_desc | range | ind_hot_endtime | ind_hot_endtime | 9 | NULL | 113549 | USING WHERE; USING filesort |

+----+-------------+----------+-------+-----------------+-----------------+---------+------+--------+-----

Ind_hot_endtime索引為:

root@test_db01:52:45:SHOW INDEX FROM test_order_desc;

Ind_hot_endtime(end_time,count_num)

在注意到sql中滿足過濾條件end_time>now()的有113549行,在加上剩余的條件中含有order by,這樣會造成排序的結果集非常的大,執行非常的耗費資源;于是分析sql,在sql中包括了order by desc limit這樣的排序條件后,新增適當的索引滿足排序的條件,同時由于有limit的限制結果集,當掃描到滿足條件的行數后退出查詢,那么我們來看看優化效果:

添加索引:

root@test 02:01:06:ALTER TABLE test_order_desc ADD INDEX ind_gmt_create(gmt_create,count_num);

Query OK, 211945 ROWS affected (6.71 sec)

Records: 211945 Duplicates: 0 Warnings: 0

再次執行sql,觀察其執行時間:

root@test 02:01:35:

SELECT * FROM test_order_desc WHERE END_TIME > now() ORDER BY GMT_CREATE DESC,count_num DESC LIMIT 12, 12;

+---------+-----------+------------+------+---------------------+---------------------+

col2...................................................................................

+---------+-----------+------------+------+---------------------+---------------------+

Data1..................................................................................

Data2..................................................................................

+---------+-----------+------------+------+---------------------+---------------------+

12 ROWS IN SET (0.00 sec)

可以看到執行時間已經降到了毫秒以下,查看其執行計劃:

root@test 02:01:42:

EXPLAIN SELECT * FROM test_order_desc WHERE END_TIME > now() ORDER BY GMT_CREATE DESC,count_num DESC LIMIT 12, 12;

+----+-------------+----------+-------+-----------------+----------------+---------+------+------+-------------+

| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | REF | ROWS | Extra |

+----+-------------+----------+-------+-----------------+----------------+---------+------+------+--------

| 1 | SIMPLE | test_order_desc | INDEX | ind_hot_endtime | ind_gmt_create | 14 | NULL | 48 | USING WHERE |

可以看到優化器已經選擇了ind_gmt_create索引掃描,這樣的話就避免了對結果集進行排序的過程,同時優化器預估掃描14行數據就會得到滿足查詢條件的數據(END_TIME > now()),執行計劃非常的理想。

root@127.0.0.1 : test_db 16:05:15:

EXPLAIN SELECT b.*,a.*,k.* FROM instance b LEFT OUTER JOIN image a ON b.image_id=a.image_id LEFT OUTER JOIN key_pair k ON b.key_pair_id=k.key_pair_id LEFT OUTER JOIN region_alias r_a ON r_a.region_no=b.region_no WHERE b.STATUS IN (1,8) AND b.user_id = 21 AND r_a.big_region_no='regeion_xx' ORDER BY b.instance_no ASC LIMIT 37300,50;

案例二:

root@127.0.0.1 : test_db 16:05:15:

EXPLAIN SELECT b.*,a.*,k.* FROM instance b LEFT OUTER JOIN image a ON b.image_id=a.image_id LEFT OUTER JOIN key_pair k ON b.key_pair_id=k.key_pair_id LEFT OUTER JOIN region_alias r_a ON r_a.region_no=b.region_no WHERE b.STATUS IN (1,8) AND b.user_id = 21 AND r_a.big_region_no='regeion_xx' ORDER BY b.instance_no ASC LIMIT 37300,50;

bf5f62816ec2f50e8ce8a2d2cc0c802d.png

B表的idx_uid_stat_inid的索引列包括了(user_id,status,instance_no):

a63ec57afe97e57b0f6f95fc4f254dcf.png

我們從執行計劃上分析來看,表的連接順序為:b—>r_a—>a—>k,可以看到執行計劃的第一行中需要掃描49212行的數據,同時由于status采用的是in的方式,instance_no即使在索引中也用不上,這樣就導致了排序使用到了臨時表,這也是導致sql執行慢的原因。我們看到sql中的最后一個排序為order by b.instance_no asc limit 37300,50,這里我們好像可以看到優化的曙光,調整數據庫的索引以滿足B表的排序需求:

root@127.0.0.1 : test_db 16:05:04 ALTER TABLE instance ADD INDEX ind_user_id(user_id,instance_no);

Query OK, 0 ROWS affected (0.56 sec)

調整索引后查看執行計劃:

root@127.0.0.1 : test_db 16:09:42

EXPLAIN SELECT b.*,a.*,k.* FROM instance b LEFT OUTER JOIN image a ON b.image_id=a.image_id LEFT OUTER JOIN key_pair k ON b.key_pair_id=k.key_pair_id LEFT OUTER JOIN region_alias r_a ON r_a.region_no=b.region_no WHERE b.STATUS IN (1,8) AND b.user_id = 21 AND r_a.big_region_no='regeion_xx' ORDER BY b.instance_no ASC LIMIT 37300,50;

6800eee8dfa3cfe14bcea0cd81c0de94.png

我們加上force index強制走我們新加的索引:

root@127.0.0.1 : test_db 16:10:24

EXPLAIN SELECT b.*,a.*,k.* FROM instance b force INDEX (ind_user_id) LEFT OUTER JOIN image a ON b.image_id=a.image_id LEFT OUTER JOIN key_pair k ON b.key_pair_id=k.key_pair_id LEFT OUTER JOIN region_alias r_a ON r_a.region_no=b.region_no WHERE b.STATUS IN (1,8) AND b.user_id = 21 AND r_a.big_region_no='regeion_xx' ORDER BY b.instance_no ASC LIMIT 37300,50;

2eeca022206f32ad800ce31e76befd25.png

可以看到在加上提示符后,使用到了我們新加的索引,掃描的行數為54580行,執行時間:

root@127.0.0.1 : test_db 16:10:30

SELECT b.*,a.*,k.* FROM instance b force INDEX (ind_user_id) LEFT OUTER JOIN image a ON b.image_id=a.image_id LEFT OUTER JOIN key_pair k ON b.key_pair_id=k.key_pair_id LEFT OUTER JOIN region_alias r_a ON r_a.region_no=b.region_no WHERE b.STATUS IN (1,8) AND b.user_id = 21 AND r_a.big_region_no='regeion_xx' ORDER BY b.instance_no ASC LIMIT 37300,50;

(0.49 sec)

原始的執行時間:

root@127.0.0.1 : test_db 16:10:51:

SELECT b.*,a.*,k.* FROM instance b LEFT OUTER JOIN image a ON b.image_id=a.image_id LEFT OUTER JOIN key_pair k ON b.key_pair_id=k.key_pair_id LEFT OUTER JOIN region_alias r_a ON r_a.region_no=b.region_no WHERE b.STATUS IN (1,8) AND b.user_id = 21 AND r_a.big_region_no='regeion_xx' ORDER BY b.instance_no ASC LIMIT 37300,50;

(1.28 sec)

總結:

Order by desc/asc limit的優化技術有時候在你無法建立很好索引的時候,往往會得到意想不到的優化效果,但有時候有一定的局限性,優化器可能不會按照你既定的索引路徑掃描,優化器需要考慮到查詢列的過濾性以及limit的長度,當查詢列的選擇性非常高的時候,使用sort的成本是不高的,當查詢列的選擇性很低的時候,那么使用order by +limit的技術是很有效的。

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

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

相關文章

leetcode441. 排列硬幣(二分查找)

你總共有 n 枚硬幣,你需要將它們擺成一個階梯形狀,第 k 行就必須正好有 k 枚硬幣。 給定一個數字 n,找出可形成完整階梯行的總行數。 n 是一個非負整數,并且在32位有符號整型的范圍內。 示例 1: n 5 硬幣可排列成以下幾行: …

【洛谷 P2051】 [AHOI2009]中國象棋(DP)

題目鏈接 首先想到狀壓dp,但是\(n,m\)高達100,怎么壓? 容易發現,每行每列最多兩個象棋,否則就直接gg了。 一個巧妙的設置狀態的方式是,只需要記錄到當前行有多少列是放了1個炮和2個炮。 然后每一行有3種選擇…

循環 直到 python_如果您在Python中存在慢循環,則可以對其進行修復……直到無法解決為止...

循環 直到 pythonby Maxim Mamaev馬克西姆馬馬耶夫(Maxim Mamaev) Let’s take a computational problem as an example, write some code, and see how we can improve the running time. Here we go.讓我們以一個計算問題為例,編寫一些代碼,看看如何改…

阿里云視頻點播解決方案使用教程

2019獨角獸企業重金招聘Python工程師標準>>> 課程介紹 視頻點播(ApsaraVideo for VoD,簡稱VoD)是集視頻音視頻采集、編輯、上傳、自動化轉碼處理、媒體資源管理、分發加速于一體的一站式音視頻點播解決方案。 產品詳情&#xff1a…

云服務器安裝操作系統后如何連接,服務器如何安裝操作系統

服務器如何安裝操作系統 內容精選換一換如果您需要使用畢昇編譯器,則需要先在服務端安裝畢昇編譯器。畢昇編譯器基于開源LLVM開發,并進行了優化和改進,同時將flang作為默認的Fortran語言前端編譯器,是針對鯤鵬平臺的高性能編譯器。…

換行符

非原創windows保留\r\n作為換行符的原因: 回車鍵為什么叫回車鍵,大家有想過沒有,字面意思是回去的車子。 第一臺打印機,每一行打印完了之后在打印第二行之前,這個噴墨的玩意兒需要先回到這一行的行首,這叫回…

leetcode劍指 Offer 53 - II. 0~n-1中缺失的數字(二分查找)

一個長度為n-1的遞增排序數組中的所有數字都是唯一的,并且每個數字都在范圍0~n-1之內。在范圍0~n-1內的n個數字中有且只有一個數字不在該數組中,請找出這個數字。 示例 1: 輸入: [0,1,3] 輸出: 2 代碼 class Solution {public…

python 0基礎起步學習day2

元組:戴上了枷鎖的列表 元組是不可改變的,元組是不能隨意改變內部的元素的 元組和列表很像,它可以看成是不可修改的列表 所以創建元祖逗號是關鍵 因為(8,)是元組,這里*就不再是乘號,而是重復拷貝符【重復操作符】 直接…

react中的狀態機_在基于狀態圖的狀態機上使用React的模式

react中的狀態機by Shawn McKay肖恩麥凱(Shawn McKay) 在基于狀態圖的狀態機上使用React的模式 (Patterns for using React with Statechart-based state machines) Statecharts and state machines offer a promising path for designing and managing complex state in apps…

android scheme打開天貓,淘寶

直接上代碼 Intent intent new Intent(); intent.setAction("android.intent.action.VIEW"); /*String url "taobao://shop.m.taobao.com/shop/shop_index.htm?shop_id131259851&spma230r.7195193.1997079397.8.Pp3ZMM&point" "%7B%22…

leetcode1337. 方陣中戰斗力最弱的 K 行(優先隊列)

給你一個大小為 m * n 的方陣 mat,方陣由若干軍人和平民組成,分別用 1 和 0 表示。 請你返回方陣中戰斗力最弱的 k 行的索引,按從最弱到最強排序。 如果第 i 行的軍人數量少于第 j 行,或者兩行軍人數量相同但 i 小于 j&#xff…

dp 1.4協議_淺析關于HDMI接口與DP接口

顯示器現在主流已經為HDMI接口與DP接口,那么這些接口都有什么區別,以下表格會大致做個區分,建議優先使用DP接口。(HDMI2.1接口目前僅發布協議,尚未大規模商用在高清電視機上有部分應用,Mini DP接口版本為DP…

淺談 JDBC 中 CreateStatement 和 PrepareStatement 的區別與優劣。

淺談 JDBC 中 CreateStatement 和 PrepareStatement 的區別與優劣。

jsp 構建單頁應用_如何使用服務器端Blazor構建單頁應用程序

jsp 構建單頁應用介紹 (Introduction) In this article, we will create a Single Page Application (SPA) using server-side Blazor. We will use an Entity Framework Core database. Single-Page Applications are web applications that load a single HTML page. They dy…

Apache的虛擬主機配置

虛擬主機配置一般可以分為:基于域名基于端口基于IP配置虛擬主機檢查防火墻,端口是否打開apache的配置文件。service iptables status #查看防火墻netstat -anp | grep 8021 #端口是必須要考慮的問題locate httpd.confmkdir -p /usr/local/apache/conf/ex…

oracle 的使用

一. docker 模式下進入數據庫 ubuntujiang:~$ sudo docker ps -a sudo: unable to resolve host jiang CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS …

sql number轉varchar_MySQL 指南之 SQL 語句基礎

個人所有文章整理在此篇,將陸續更新收錄:知無涯,行者之路莫言終(我的編程之路)零、結構化查詢語言:SQL(Structured Query Language)DDL 數據定義語言 管理庫,表DML 數據操作語言 增刪改查 DCL 數據控制語言 數據控制,權…

leetcode744. 尋找比目標字母大的最小字母(二分查找)

給你一個排序后的字符列表 letters ,列表中只包含小寫英文字母。另給出一個目標字母 target,請你尋找在這一有序列表里比目標字母大的最小字母。 在比較時,字母是依序循環出現的。舉個例子: 如果目標字母 target ‘z’ 并且字符…

H3C交換機 匯聚接口上應用策略路由

QOS 方式的策略路由只能應用在接口或者Vlan接口上,無法應用在2層或者3層的匯聚接口上可以使用PBR的方式將策略路由應用到接口上,QOS策略路由可以和PBR策略路由共存,并且QOS的優先級更高,先匹配QOS,如果匹配不到再匹配P…

【Java NIO深入研究3】文件鎖

1.1概述——文件鎖 文件鎖定初看起來可能讓人迷惑。它 似乎 指的是防止程序或者用戶訪問特定文件。事實上,文件鎖就像常規的 Java 對象鎖 — 它們是 勸告式的(advisory) 鎖。它們不阻止任何形式的數據訪問,相反,它們通…