經驗分享:一次非常有趣的SQL優(yōu)化過程
掃描二維碼
隨時隨地手機看文章
本文來源:
https://www.cnblogs.com/tangyanbo/p/4462734.html
場景
索引優(yōu)化
單列索引
多列索引
索引覆蓋
排序
場景
create table Course(
c_id int PRIMARY KEY,
name varchar(10)
)
數據100條
學生表:
create table Student(
id int PRIMARY KEY,
name varchar(10)
)
數據70000條
學生成績表SC
CREATE table SC(
sc_id int PRIMARY KEY,
s_id int,
c_id int,
score int
)
數據70w條
查詢目的:
查找語文考100分的考生
查詢語句:
select s.* from Student s where s.s_id in (select s_id from SC sc where sc.c_id = 0 and sc.score = 100 )
執(zhí)行時間:30248.271s
暈,為什么這么慢,先來查看下查詢計劃:
EXPLAIN
select s.* from Student s where s.s_id in (select s_id from SC sc where sc.c_id = 0 and sc.score = 100 )

CREATE index sc_c_id_index on SC(c_id);
CREATE index sc_score_index on SC(score);

查看優(yōu)化后的sql:
SELECT
`YSB`.`s`.`s_id` AS `s_id`,
`YSB`.`s`.`name` AS `name`
FROM
`YSB`.`Student` `s`
WHERE
< in_optimizer > (
`YSB`.`s`.`s_id` ,< EXISTS > (
SELECT
1
FROM
`YSB`.`SC` `sc`
WHERE
(
(`YSB`.`sc`.`c_id` = 0)
AND (`YSB`.`sc`.`score` = 100)
AND (
< CACHE > (`YSB`.`s`.`s_id`) = `YSB`.`sc`.`s_id`
)
)
)
)


select s_id from SC sc where sc.c_id = 0 and sc.score = 100
耗時:0.001s
得到如下結果:

然后再執(zhí)行
select s.* from Student s where s.s_id in(7,29,5000)
耗時:0.001s
SELECT s.* from
Student s
INNER JOIN SC sc
on sc.s_id = s.s_id
where sc.c_id=0 and sc.score=100



優(yōu)化后的查詢語句為:
SELECT
`YSB`.`s`.`s_id` AS `s_id`,
`YSB`.`s`.`name` AS `name`
FROM
`YSB`.`Student` `s`
JOIN `YSB`.`SC` `sc`
WHERE
(
(
`YSB`.`sc`.`s_id` = `YSB`.`s`.`s_id`
)
AND (`YSB`.`sc`.`score` = 100)
AND (`YSB`.`sc`.`c_id` = 0)
)


SELECT
s.*
FROM
(
SELECT
*
FROM
SC sc
WHERE
sc.c_id = 0
AND sc.score = 100
) t
INNER JOIN Student s ON t.s_id = s.s_id

CREATE index sc_c_id_index on SC(c_id);
CREATE index sc_score_index on SC(score);
再執(zhí)行查詢:
SELECT
s.*
FROM
(
SELECT
*
FROM
SC sc
WHERE
sc.c_id = 0
AND sc.score = 100
) t
INNER JOIN Student s ON t.s_id = s.s_id
執(zhí)行時間為:0.001s,這個時間相當靠譜,快了50倍
執(zhí)行計劃:

我們會看到,先提取sc,再連表,都用到了索引。
那么再來執(zhí)行下sql
SELECT s.* from
Student s
INNER JOIN SC sc
on sc.s_id = s.s_id
where sc.c_id=0 and sc.score=100
執(zhí)行時間0.001s
執(zhí)行計劃:


執(zhí)行sql
SELECT s.* from
Student s
INNER JOIN SC sc
on sc.s_id = s.s_id
where sc.c_id=81 and sc.score=84
執(zhí)行時間:0.061s,這個時間稍微慢了點
執(zhí)行計劃:

alter table SC drop index sc_c_id_index;
alter table SC drop index sc_score_index;
create index sc_c_id_score_index on SC(c_id,score);

索引優(yōu)化
單列索引
select * from user_test_copy where sex = 2 and type = 2 and age = 10
索引:
CREATE index user_test_index_sex on user_test_copy(sex);
CREATE index user_test_index_type on user_test_copy(type);
CREATE index user_test_index_age on user_test_copy(age);
分別對sex,type,age字段做了索引,數據量為300w,查詢時間:0.415s
執(zhí)行計劃:

發(fā)現type=index_merge
這是mysql對多個單列索引的優(yōu)化,對結果集采用intersect并集操作
多列索引
我們可以在這3個列上建立多列索引,將表copy一份以便做測試
create index user_test_index_sex_type_age on user_test(sex,type,age);
查詢語句:
select * from user_test where sex = 2 and type = 2 and age = 10
執(zhí)行時間:0.032s,快了10多倍,且多列索引的區(qū)分度越高,提高的速度也越多
執(zhí)行計劃:

最左前綴
多列索引還有最左前綴的特性:
執(zhí)行一下語句:
select * from user_test where sex = 2
select * from user_test where sex = 2 and type = 2
select * from user_test where sex = 2 and age = 10
索引覆蓋
select sex,type,age from user_test where sex = 2 and type = 2 and age = 10
執(zhí)行時間:0.003s
要比取所有字段快的多
排序
select * from user_test where sex = 2 and type = 2 ORDER BY user_name
時間:0.139s
在排序字段上建立索引會提高排序的效率
create index user_name_index on user_test(user_name)
最后附上一些sql調優(yōu)的總結,以后有時間再深入研究
列類型盡量定義成數值類型,且長度盡可能短,如主鍵和外鍵,類型字段等等
建立單列索引
根據需要建立多列聯合索引
當單個列過濾之后還有很多數據,那么索引的效率將會比較低,即列的區(qū)分度較低,
那么如果在多個列上建立索引,那么多個列的區(qū)分度就大多了,將會有顯著的效率提高。
根據業(yè)務場景建立覆蓋索引
只查詢業(yè)務需要的字段,如果這些字段被索引覆蓋,將極大的提高查詢效率
多表連接的字段上需要建立索引
這樣可以極大的提高表連接的效率
where條件字段上需要建立索引
排序字段上需要建立索引
分組字段上需要建立索引
Where條件上不要使用運算函數,以免索引失效
作者:風過無痕的博客
來源:www.cnblogs.com/tangyanbo/p/4462734.html
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!