先查看表是否已經(jīng)存有索引:
10年積累的做網(wǎng)站、成都網(wǎng)站制作經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有九龍坡免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
show index from 表名
語法:alter table 表名 add index 索引名稱(字段名稱)
UNIQUE(唯一索引)ALTER TABLE `table_name` ADD UNIQUE (`column`)
查詢索引:
1. 執(zhí)行計(jì)劃中明明有使用到索引,為什么執(zhí)行還是這么慢?
2. 執(zhí)行計(jì)劃中顯示掃描行數(shù)為 644,為什么 slow log 中顯示 100 多萬行?
a. 我們先看執(zhí)行計(jì)劃,選擇的索引 “INDX_BIOM_ELOCK_TASK3(TASK_ID)”。結(jié)合 sql 來看,因?yàn)橛?"ORDER BY TASK_ID DESC" 子句,排序通常很慢,如果使用了文件排序性能會(huì)更差,優(yōu)化器選擇這個(gè)索引避免了排序。
那為什么不選 possible_keys:INDX_BIOM_ELOCK_TASK 呢?原因也很簡(jiǎn)單,TASK_DATE 字段區(qū)分度太低了,走這個(gè)索引需要掃描的行數(shù)很大,而且還要進(jìn)行額外的排序,優(yōu)化器綜合判斷代價(jià)更大,所以就不選這個(gè)索引了。不過如果我們強(qiáng)制選擇這個(gè)索引(用 force index 語法),會(huì)看到 SQL 執(zhí)行速度更快少于 10s,那是因?yàn)閮?yōu)化器基于代價(jià)的原則并不等價(jià)于執(zhí)行速度的快慢;
b. 再看執(zhí)行計(jì)劃中的 type:index,"index" 代表 “全索引掃描”,其實(shí)和全表掃描差不多,只是掃描的時(shí)候是按照索引次序進(jìn)行而不是行,主要優(yōu)點(diǎn)就是避免了排序,但是開銷仍然非常大。
Extra:Using where 也意味著掃描完索引后還需要回表進(jìn)行篩選。一般來說,得保證 type 至少達(dá)到 range 級(jí)別,最好能達(dá)到 ref。
在第 2 點(diǎn)中提到的“慢日志記錄Rows_examined: 1161559,看起來是全表掃描”,這里更正為“全索引掃描”,掃描行數(shù)確實(shí)等于表的行數(shù);
c. 關(guān)于執(zhí)行計(jì)劃中:“rows:644”,其實(shí)這個(gè)只是估算值,并不準(zhǔn)確,我們分析慢 SQL 時(shí)判斷準(zhǔn)確的掃描行數(shù)應(yīng)該以 slow log 中的 Rows_examined 為準(zhǔn)。
4. 優(yōu)化建議:添加組合索引 IDX_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID)
優(yōu)化過程:
TASK_DATE 字段存在索引,但是選擇度很低,優(yōu)化器不會(huì)走這個(gè)索引,建議后續(xù)可以刪除這個(gè)索引:
select count(*),count(distinct TASK_DATE) from T_BIOMA_ELOCK_TASK;+------------+---------------------------+| count(*) | count(distinct TASK_DATE) |+------------+---------------------------+| 1161559 | 223 |+------------+---------------------------+
在這個(gè) sql 中 REL_DEVID 字段從命名上看選擇度較高,通過下面 sql 來檢驗(yàn)確實(shí)如此:
select count(*),count(distinct REL_DEVID) from T_BIOMA_ELOCK_TASK;+----------+---------------------------+| count(*) | count(distinct REL_DEVID) |+----------+---------------------------+| 1161559 | 62235 |+----------+---------------------------+
由于有排序,所以得把 task_id 也加入到新建的索引中,REL_DEVID,task_id 組合選擇度 100%:
select count(*),count(distinct REL_DEVID,task_id) from T_BIOMA_ELOCK_TASK;+----------+-----------------------------------+| count(*) | count(distinct REL_DEVID,task_id) |+----------+-----------------------------------+| 1161559 | 1161559 |+----------+-----------------------------------+
在測(cè)試環(huán)境添加 REL_DEVID,TASK_ID 組合索引,測(cè)試 sql 性能:alter table T_BIOMA_ELOCK_TASK add index idx_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID);
添加索引后執(zhí)行計(jì)劃:
這里還要注意一點(diǎn)“隱式轉(zhuǎn)換”:REL_DEVID 字段數(shù)據(jù)類型為 varchar,需要在 sql 中加引號(hào):AND T.REL_DEVID = 000000025xxx AND T.REL_DEVID = '000000025xxx'
執(zhí)行時(shí)間從 10s+ 降到 毫秒級(jí)別:
1 row in set (0.00 sec)
結(jié)論
一個(gè)典型的 order by 查詢的優(yōu)化,添加更合適的索引可以避免性能問題:執(zhí)行計(jì)劃使用索引并不意味著就能執(zhí)行快。
一般情況下,mysql會(huì)根據(jù)查詢,自動(dòng)判斷并使用對(duì)應(yīng)的索引,不需要索引名稱,
有些情況下,如果你能確保你的查詢有問題,可以使用強(qiáng)制索引,如:
select * from table1 force index(索引名稱)
或者強(qiáng)制不允許使用指定的索引:
select * from table1 ignore index(索引名稱)