資料庫優化 記一次Mysql的優化經歷

2022-06-30 06:54:07 字數 3981 閱讀 8248

1.建立乙個課程表

create table course(

c_id int primary key,

name varchar(10)

)

2.建立乙個學生表
create table student(

s_id int primary key,

name varchar(10)

)

3.建立乙個課程學生表
create table sc(

sc_id int primary key,

s_id int,

c_id int,

score int

)

4.通過儲存過程 插入七十萬的資料
delimiter $$

create procedure insert_dept(in start int(10),in max_num int(10))

begin

declare i int default 0;

set autocommit = 0;

repeat

set i=i+ 1;

insert into course(c_id ,name) values ((start+i),concat("語文"));

until i = max_num

end repeat;

commit;

end $$

delimiter $$

create procedure insert_dept(in start int(10),in max_num int(10))

begin

declare i int default 0;

set autocommit = 0;

repeat

set i=i+ 1;

insert into student(id ,name) values (start+i,(concat("小明",i)));

until i = max_num

end repeat;

commit;

end $$

5.查詢語文成績為89的學生資訊
select * from student s where s.s_id in (select sc.s_id from sc sc where sc.score = 89 and sc.c_id = 1)
​ 執行後發現時間要的很久,我直接停止查詢了

然後我們建立索引,提高查詢速度

drop index  idx_sc_score on sc;

drop index idx_sc_c_id on sc;

create index idx_sc_score on sc(score);

create index idx_sc_c_id on sc(c_id);

查詢發現還是很慢,檢視一下查詢計畫

存在全表掃瞄,速度太慢了

檢視一下mysql的處理執行器優化過後的sql

在explain extended 後執行show warning

explain extended select * from student s where s.s_id in (select sc.s_id from sc sc where sc.score = 89 and sc.c_id = 1);

show warnings

可以看到優化後的sql

select

`crm`.`s`.`s_id` as `s_id`,

`crm`.`s`.`name` as `name`

from

`crm`.`student` `s`

where

< in_optimizer > (

`crm`.`s`.`s_id` ,< exists > (

select

1from

`crm`.`sc`

where

((`crm`.`sc`.`c_id` = 1)

and (`crm`.`sc`.`score` = 89)

and (

< cache > (`crm`.`s`.`s_id`) = `crm`.`sc`.`s_id`))

) )

可以看到mysql 經過優化後 將in修改為exists

select count(1) from sc sc where sc.score = 89 and sc.c_id = 1

:1162

這個不符合exists後接大表的原則,需要迴圈700000*1162次

所以可以通過連表查詢:

select * from student s inner join sc sc on s.s_id = sc.sc_id where sc.score = 89 and sc.c_id = 1
這樣的話,速度快了很多 0.416s

檢視執行計畫:

還是有可以優化的空間

檢視一下優化過後的sql

select

`crm`.`s`.`s_id` as `s_id`,

`crm`.`s`.`name` as `name`,

`crm`.`sc`.`sc_id` as `sc_id`,

`crm`.`sc`.`s_id` as `s_id`,

`crm`.`sc`.`c_id` as `c_id`,

`crm`.`sc`.`score` as `score`

from

`crm`.`student` `s`

join `crm`.`sc`

where

( (

`crm`.`s`.`s_id` = `crm`.`sc`.`sc_id`

) and (`crm`.`sc`.`c_id` = 1)

and (`crm`.`sc`.`score` = 89)

)

先連表在去通過where條件過濾,還是很大,可以先將sc表中過濾後再去連表

select s.* from (select sc.s_id from sc sc where sc.score = 89 and sc.c_id = 1) t inner join student s on s.s_id = t.s_id
這樣子以後,速度更快了0.121s

檢視執行計畫

!(....\image\資料庫\explain 03.png)

這裡用到了intersect 這樣並集操作,就是兩個索引同事檢索,然後再求並集

在看score 和c_id這兩個字段,區分度不高,我們可以建立聯合索引,也可以提交高區分度

create index ind_sc_score_id on sc(score,s_id)
刪除之前的索引,然後執行後發現 0.056s快了一倍

這樣還可以了

總結:列型別盡量定義成數值型別,且長度盡可能短,如主鍵和外來鍵,型別字段等等

建立單列索引

根據需要建立多列聯合索引

當單個列過濾之後還有很多資料,那麼索引的效率將會比較低,即列的區分度較低,

那麼如果在多個列上建立索引,那麼多個列的區分度就大多了,將會有顯著的效率提高。

根據業務場景建立覆蓋索引

只查詢業務需要的字段,如果這些欄位被索引覆蓋,將極大的提高查詢效率

多表連線的字段上需要建立索引

這樣可以極大的提高表連線的效率

where條件欄位上需要建立索引

排序欄位上需要建立索引

分組欄位上需要建立索引

where條件上不要使用運算函式,以免索引失效

記一次MySQL資料庫crash事件

mysql8.0資料庫最近一次不知道怎麼回事,突然啟動不了,如下提示 mysql daemon failed to start 日誌如下 網上也找了很多資料,但都處理不了 因為本人安裝資料庫習慣將安裝好的資料庫移到移到其他目錄,所以做了乙個操作,用原來的覆蓋現有的檔案 左邊是原始資料庫檔案,右邊是移...

記一次MySQL索引優化

兩張表是主 check drawings 從 check drawings img 關係。check drawings,主表資料 3591條。select count from check drawings 3591 check drawings img,從表資料107203條,資料量並不大,從表通...

mysql資料庫翻核 記一次mysql的調優

問題現象 mysql cpu占用188 多核 解決方法 1.跟蹤慢查詢 vi etc my.cnf 在mysqld下增加如下內容 log slow queries slow.log long query time 5 含義為記錄查詢時間超過5秒的sql到slow.log 查詢slow.log的內容,...