mysql 架构优化_Mysql 架构及优化之-查询性能优化
①②③④⑤⑥⑦⑧⑨
查詢執行基礎知識
mysql執行查詢過程
① 客戶端將查詢發送到服務器
② 服務器檢查查詢緩存 如果找到了就從緩存返回結果 否則進行下一步
③ 服務器解析,預處理和優化查詢,生成執行計劃
④ 執行引擎調用存儲引擎api執行查詢
⑤ 服務器將結果發送回客戶端
mysql客戶端/服務器協議
該協議是半雙工通信,可以發送或接收數據,但是不能同時發送和接收決定了mysql的溝通簡單又快捷
缺點:無法進行流程控制,一旦一方發送消息,另一方在發送回復之前必須提取完整的消息,就像
拋球游戲,任意時間,只有某一方有球,而且有球在手上,否則就不能把球拋出去(發送消息)
mysql客戶端發送/服務器響應
可以設定max_packet_size這個參數控制客戶端發送的數據包(一旦發送數據包,唯一做的就是等待結果)
服務器發送的響應由多個數據包組成, 客戶端必須完整接收結果,即使只需要幾行數據,也得等到全部接收 然后丟掉,或者強制斷開連接
(這兩個方法好挫,所以我們使用limit子句呀!!)
也可以理解,客戶端從服務器 "拉" 數據 ,實際是服務器產生數據 "推"到客戶端, 客戶端不能說不要 是必須全部裝著 !!
常用的Mysql類庫 其實是從客戶端提取數據 緩存到array(內存)中,然后進行 foreach 處理
但是對于龐大的結果集裝載在內存中需要很長時間 如果不緩存 使用較少的內存并且可以盡快工作 但是應用程序和類庫交互時候
服務器端的鎖和資源都是被鎖定的
查詢狀態
每個mysql連接都是mysql服務器的一個線程 任意一個給定的時間都有一個狀態來標識正在發生的事情
使用 show full processlist 命令查看
mysql中一共有12個狀態
休眠 查詢 鎖定 分析和統計 拷貝到磁盤上的臨時表 排序結果 發送數據
通過這些狀態 知道 "球在誰手上"
查詢緩存
解析一個查詢 如果開啟了緩存 mysql會檢查查詢緩存 發現緩存匹配 返回緩存之前 檢查查詢的權限
優化數據訪問
查詢性能低下最基本的原因是訪問了太多的數據
分析兩方面:
① 查明應用程序是否獲取超過需要的數據 通常意味著訪問了過多的行或列
② 查明mysql服務器是否分析了超過需要的行
向服務器請求了不需要的數據
一般請求不需要的數據 再丟掉他們 造成服務器額外的負擔 增加網絡開銷 消耗了內存和cpu
典型的錯誤:
① 提取超過需要的行 => 添加 limit 10 控制獲取行數
② 多表聯接提取所有列 => select fruit.* from fruit left join fruit_juice where
.....
③ 提取所有的列 => select id,name... from fruit ... (有時提取超過需要的數據便于復用)
mysql檢查了太多數據
簡單的開銷指標:執行時間 、 檢查的行數 、返回的行數
以上三個指標寫入了慢查詢日志 可以使用 mysqlsla工具進行日志分析
① 執行時間:執行時間只是參考 不可一概而論 因為執行時間 和服務器當時負載有關
② 檢查和返回的行:理想情況下返回的行和檢查的行一樣,但是顯示基本不可能 比如聯接查詢
③ 檢查的行和訪問類型: 使用 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子句 從最好到最壞依次是:
① 對索引查找應用where子句來消除不匹配的行 這發生在存儲層
② 使用覆蓋索引(extra 列 "using index") 避免訪問行 從索引取得數據過濾不匹配的行 這發生在服務層不需要從表中讀取行
③ 從表中檢索出數據 過濾不匹配的行(extra:using where)
如果發現訪問數據行數很大,嘗試以下措施:
① 使用覆蓋索引 ,存儲了數據 存儲引擎不會讀取完整的行
② 更改架構使用匯總表
③ 重寫復雜的查詢 讓mysql優化器優化執行它
重構查詢的方式
優化有問題的查詢 其實也可以找到替代方案 提供更高的效率
復雜查詢和多個查詢
mysql一般服務器可以每秒50000個查詢
常規情況下,使用盡可能少的查詢 有時候分解查詢得到更高的效率
縮短查詢
分治法,查詢本質上不變,每次執行一小部分,以減少受影響的行數
比如清理陳舊的數據 每次清理1000條
delete from message where create < date_sub(now(),inteval 3 month)
limit 1000
防止長時間鎖住很多行的數據
分解聯接
把一個多表聯接分解成多個單個查詢 然后在應用程序實現聯接操作
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)
第一眼看上去比較浪費,因為增加了查詢數量,但是有重大的性能優勢
① 緩存效率高,應用程序直接緩存了表 類似第一個查詢直接跳過
② 對于myisam表來說 每個表一個查詢有效利用表鎖 查詢鎖住表的時間縮短
③ 應用程端進行聯接更方便擴展數據庫
④ 使用in() 避免聯表查詢id排序的耗費
⑤ 減少多余行的訪問 , 意味著每行數據只訪問一次 避免聯接查詢的非正則化的架構帶來的反復訪問同一行的弊端
分解聯接應用場景:
① 可以緩存早期查詢的大量的數據
② 使用了多個myisam表(mysiam表鎖 并發時候 一條sql鎖住多個表 所以要分解)
③ 數據分布在不同的服務器上
④ 對于大表使用in() 替換聯接
⑤ 一個聯接引用了同一個表很多次
提取隨機行
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時觸發外鍵
表student數據
表student_extend數據
刪除表student一條數據 則 外鍵表就會觸發外鍵 刪除對應數據
delete from student where id = 2;
優化聯合查詢
select * from A limit 10 union all select * from B limit 10
優化max() min()
其中 name 沒有索引
select min(id) from fruit where name = "banana"
==>
select id from fruit use index(PRIMARY) where name = 'banana' limit 1
對一個表同時進行select 和 update
總結
以上是生活随笔為你收集整理的mysql 架构优化_Mysql 架构及优化之-查询性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nestjs连接远程mysql_Nest
- 下一篇: mysql建表用的什么语句_mysql建