mysql 架构优化_Mysql 架构及优化之-查询性能优化
①②③④⑤⑥⑦⑧⑨
查詢執(zhí)行基礎(chǔ)知識
mysql執(zhí)行查詢過程
① 客戶端將查詢發(fā)送到服務(wù)器
② 服務(wù)器檢查查詢緩存 如果找到了就從緩存返回結(jié)果 否則進(jìn)行下一步
③ 服務(wù)器解析,預(yù)處理和優(yōu)化查詢,生成執(zhí)行計劃
④ 執(zhí)行引擎調(diào)用存儲引擎api執(zhí)行查詢
⑤ 服務(wù)器將結(jié)果發(fā)送回客戶端
mysql客戶端/服務(wù)器協(xié)議
該協(xié)議是半雙工通信,可以發(fā)送或接收數(shù)據(jù),但是不能同時發(fā)送和接收決定了mysql的溝通簡單又快捷
缺點(diǎn):無法進(jìn)行流程控制,一旦一方發(fā)送消息,另一方在發(fā)送回復(fù)之前必須提取完整的消息,就像
拋球游戲,任意時間,只有某一方有球,而且有球在手上,否則就不能把球拋出去(發(fā)送消息)
mysql客戶端發(fā)送/服務(wù)器響應(yīng)
可以設(shè)定max_packet_size這個參數(shù)控制客戶端發(fā)送的數(shù)據(jù)包(一旦發(fā)送數(shù)據(jù)包,唯一做的就是等待結(jié)果)
服務(wù)器發(fā)送的響應(yīng)由多個數(shù)據(jù)包組成, 客戶端必須完整接收結(jié)果,即使只需要幾行數(shù)據(jù),也得等到全部接收 然后丟掉,或者強(qiáng)制斷開連接
(這兩個方法好挫,所以我們使用limit子句呀!!)
也可以理解,客戶端從服務(wù)器 "拉" 數(shù)據(jù) ,實(shí)際是服務(wù)器產(chǎn)生數(shù)據(jù) "推"到客戶端, 客戶端不能說不要 是必須全部裝著 !!
常用的Mysql類庫 其實(shí)是從客戶端提取數(shù)據(jù) 緩存到array(內(nèi)存)中,然后進(jìn)行 foreach 處理
但是對于龐大的結(jié)果集裝載在內(nèi)存中需要很長時間 如果不緩存 使用較少的內(nèi)存并且可以盡快工作 但是應(yīng)用程序和類庫交互時候
服務(wù)器端的鎖和資源都是被鎖定的
查詢狀態(tài)
每個mysql連接都是mysql服務(wù)器的一個線程 任意一個給定的時間都有一個狀態(tài)來標(biāo)識正在發(fā)生的事情
使用 show full processlist 命令查看
mysql中一共有12個狀態(tài)
休眠 查詢 鎖定 分析和統(tǒng)計 拷貝到磁盤上的臨時表 排序結(jié)果 發(fā)送數(shù)據(jù)
通過這些狀態(tài) 知道 "球在誰手上"
查詢緩存
解析一個查詢 如果開啟了緩存 mysql會檢查查詢緩存 發(fā)現(xiàn)緩存匹配 返回緩存之前 檢查查詢的權(quán)限
優(yōu)化數(shù)據(jù)訪問
查詢性能低下最基本的原因是訪問了太多的數(shù)據(jù)
分析兩方面:
① 查明應(yīng)用程序是否獲取超過需要的數(shù)據(jù) 通常意味著訪問了過多的行或列
② 查明mysql服務(wù)器是否分析了超過需要的行
向服務(wù)器請求了不需要的數(shù)據(jù)
一般請求不需要的數(shù)據(jù) 再丟掉他們 造成服務(wù)器額外的負(fù)擔(dān) 增加網(wǎng)絡(luò)開銷 消耗了內(nèi)存和cpu
典型的錯誤:
① 提取超過需要的行 => 添加 limit 10 控制獲取行數(shù)
② 多表聯(lián)接提取所有列 => select fruit.* from fruit left join fruit_juice where
.....
③ 提取所有的列 => select id,name... from fruit ... (有時提取超過需要的數(shù)據(jù)便于復(fù)用)
mysql檢查了太多數(shù)據(jù)
簡單的開銷指標(biāo):執(zhí)行時間 、 檢查的行數(shù) 、返回的行數(shù)
以上三個指標(biāo)寫入了慢查詢?nèi)罩?可以使用 mysqlsla工具進(jìn)行日志分析
① 執(zhí)行時間:執(zhí)行時間只是參考 不可一概而論 因?yàn)閳?zhí)行時間 和服務(wù)器當(dāng)時負(fù)載有關(guān)
② 檢查和返回的行:理想情況下返回的行和檢查的行一樣,但是顯示基本不可能 比如聯(lián)接查詢
③ 檢查的行和訪問類型: 使用 explain sql語句 觀察 type 列
typ列:(訪問速度依次遞增)
① 全表掃描(full table scan)
② 索引掃描(index scan)
③ 范圍掃描(range scan)
④ 唯一索引查找(unique index lookup)
⑤ 常量(constant)
可見 type 列為 index 即 sql 語句 基于 索引掃描
rows 列 為 12731 即 掃描了 12731 行
extra列為 using index 即 使用索引過濾不需要的行
mysql會在3種情況下使用where子句 從最好到最壞依次是:
① 對索引查找應(yīng)用where子句來消除不匹配的行 這發(fā)生在存儲層
② 使用覆蓋索引(extra 列 "using index") 避免訪問行 從索引取得數(shù)據(jù)過濾不匹配的行 這發(fā)生在服務(wù)層不需要從表中讀取行
③ 從表中檢索出數(shù)據(jù) 過濾不匹配的行(extra:using where)
如果發(fā)現(xiàn)訪問數(shù)據(jù)行數(shù)很大,嘗試以下措施:
① 使用覆蓋索引 ,存儲了數(shù)據(jù) 存儲引擎不會讀取完整的行
② 更改架構(gòu)使用匯總表
③ 重寫復(fù)雜的查詢 讓mysql優(yōu)化器優(yōu)化執(zhí)行它
重構(gòu)查詢的方式
優(yōu)化有問題的查詢 其實(shí)也可以找到替代方案 提供更高的效率
復(fù)雜查詢和多個查詢
mysql一般服務(wù)器可以每秒50000個查詢
常規(guī)情況下,使用盡可能少的查詢 有時候分解查詢得到更高的效率
縮短查詢
分治法,查詢本質(zhì)上不變,每次執(zhí)行一小部分,以減少受影響的行數(shù)
比如清理陳舊的數(shù)據(jù) 每次清理1000條
delete from message where create < date_sub(now(),inteval 3 month)
limit 1000
防止長時間鎖住很多行的數(shù)據(jù)
分解聯(lián)接
把一個多表聯(lián)接分解成多個單個查詢 然后在應(yīng)用程序?qū)崿F(xiàn)聯(lián)接操作
select * from teacher
join school on teacher.id = school.id
join course on teacher.id = course.id
where course.name= 'english'
使用一下語句代替
select * from course where name = 'english'
select * from teacher where course_id = 1024
select * from school where teacher_id in (111,222,333)
第一眼看上去比較浪費(fèi),因?yàn)樵黾恿瞬樵償?shù)量,但是有重大的性能優(yōu)勢
① 緩存效率高,應(yīng)用程序直接緩存了表 類似第一個查詢直接跳過
② 對于myisam表來說 每個表一個查詢有效利用表鎖 查詢鎖住表的時間縮短
③ 應(yīng)用程端進(jìn)行聯(lián)接更方便擴(kuò)展數(shù)據(jù)庫
④ 使用in() 避免聯(lián)表查詢id排序的耗費(fèi)
⑤ 減少多余行的訪問 , 意味著每行數(shù)據(jù)只訪問一次 避免聯(lián)接查詢的非正則化的架構(gòu)帶來的反復(fù)訪問同一行的弊端
分解聯(lián)接應(yīng)用場景:
① 可以緩存早期查詢的大量的數(shù)據(jù)
② 使用了多個myisam表(mysiam表鎖 并發(fā)時候 一條sql鎖住多個表 所以要分解)
③ 數(shù)據(jù)分布在不同的服務(wù)器上
④ 對于大表使用in() 替換聯(lián)接
⑤ 一個聯(lián)接引用了同一個表很多次
提取隨機(jī)行
select * from area order by rand() limit 5;
分組查詢
select cname,pname,count(pname) from user by (cname pname with rollup )
外鍵
只有Innodb引擎支持外鍵,myisam可以添加外鍵但是沒有效果
主表添加主鍵id 從表添加外鍵id引用主表的id
表student
create table `student` (
`id` int(11) not null auto_increment,
`name` varchar(255) default null,
primary key (`id`)
) engine=innodb auto_increment=7 default charset=utf8
表student_extend
create table `student_extend` (
`student_id` int(11) default null,
`age` smallint(5) default null,
key `student_id` (`student_id`),
constraint `student_index` foreign key (`student_id`)
references `student` (`id`) on delete cascade on update no action
) engine=innodb default charset=utf8
為student_extend添加外鍵 外鍵指向 student 表中的id 列 在delete時觸發(fā)外鍵
表student數(shù)據(jù)
表student_extend數(shù)據(jù)
刪除表student一條數(shù)據(jù) 則 外鍵表就會觸發(fā)外鍵 刪除對應(yīng)數(shù)據(jù)
delete from student where id = 2;
優(yōu)化聯(lián)合查詢
select * from A limit 10 union all select * from B limit 10
優(yōu)化max() min()
其中 name 沒有索引
select min(id) from fruit where name = "banana"
==>
select id from fruit use index(PRIMARY) where name = 'banana' limit 1
對一個表同時進(jìn)行select 和 update
總結(jié)
以上是生活随笔為你收集整理的mysql 架构优化_Mysql 架构及优化之-查询性能优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nestjs连接远程mysql_Nest
- 下一篇: mysql建表用的什么语句_mysql建