令人頭大的慢查詢分析
前言
建表語句
create table student(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`age` INT(11) NOT NULL,
`height` INT(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `name_index` (`name`),
KEY `multi_index` (`age`,`height`)
);
explain命名使用方法
explain命令,主要可以對
select
語句進行分析,並輸出select
執行的詳細信息,以供開發人員針對性優化。explian
的使用十分簡單,在select語句前面加上explain
關鍵字即可,如下圖,其中order_id
是主鍵
輸出的各個屬性含義
id | select 查詢的標識符,是唯一的 |
---|---|
select_type | select查詢類型 |
table | 查詢指定的表 |
partitions | 匹配的分區 |
type | 訪問類型,ALL指的是全表掃描 |
possible_keys | 查詢中可能使用的索引 |
key | 查詢中確切使用到的索引 |
ref | 哪個字段或常數與 key 一起被使用 |
rows | 顯示此查詢一共掃描的行數,是一個估計值. |
filtered | 查詢條件所過濾的數據的百分比 |
extra | 額外信息 |
索引失效情況
-
最佳左前綴法則
如果索引是複合索引,要遵循最佳左前綴法則,查詢從索引的最前列開始,並且不跳過索引中的列
下面是違反最佳左前綴法則的情況,針對複合索引(age, height), 直接根據height查詢,則複合索引失效
-
在索引上做操作(計算、函數、類型轉換),均會導致索引失效
如下圖,對主鍵id,進行 id+1操作,會使索引失效
-
索引字段上使用(is null, not null)判斷時,會使索引失效
-
索引字段使用like以通配符%開頭時,會導致索引失效
-
索引字段中使用or
慢查詢分析
msql通過指定long_query_time參數,設置慢查詢的時間閾值,一旦查詢語句的執行時間超過此參數,其就會被系統記錄到慢查詢日誌中。通過對慢查詢日誌進行分析,可以對相應的慢查詢語句或者數據庫進行優化,從而提升數據庫性能。下面詳細講述幾種造成慢查詢的原因和優化手段。
-
上文提到的索引失效
-
limit分頁語句偏移量過大
limit語句的查詢時間與偏移量成正比,所以一旦偏移量過大會造成查詢速度巨慢
使用子查詢優化
原查詢語句
select * from student limit 200000, 20;
優化後查詢語句(id是主鍵索引)
select * from student where id >=(select id from student limit 200000, 1) limit 20;
-
數據庫在刷髒頁
數據庫的每一次修改(插入、刪除、更新)操作,都會記錄在
redo log
日誌,redo log
日誌一般不會直接刷新到磁盤中,而是保存在緩衝區(os buffer
),等操作系統空閒的時候,刷新進磁盤。但是緩衝區容量是有限的,如果數據庫更新過於頻繁,導致緩衝區滿了,就不會等系統空閒,而是直接暫停其他操作,將緩衝區刷新進磁盤中。所以此時執行查詢語句就會特別慢。 -
鎖衝突
數據庫一般支持表鎖,或者行鎖。拿表鎖舉例,如果一個sql語句,獲取表的寫鎖後,在執行更新操作,之後的查詢(
select
)語句,需要等待表寫鎖釋放,才能獲取讀鎖。所以一旦查詢語句執行涉及到的鎖,被其他sql語句佔有,無法獲取鎖,需要等待其釋放鎖,所以會造成查詢慢。