騰訊課堂,燕十八Mysql高性能優化https://ke.qq.com/course/171224
建表原則
- 變長字段和定長字段分離
- 常用字段和不常用字段分離
- 在1對多,需要關聯統計的字段上,添加冗余字段以減少查詢的壓力,寫入的時候麻煩一點
列類型選擇
- 字段類型優先級 整型>date,time>enum,char>varcahr>blob,text
- 性別:utf8為例
- char(1)三個字節
- enum('男','女')內部轉成數字來存,多了一個轉換過程
- tinyint(),0,1,2 定長1字節
- 夠用就行,不要慷慨
- 年齡:用 tinyint unsigned not null足夠,可以存0-255
- varchar(10),varcahr(300)存儲內容相同,但是在聯查時,后者占用更多內存
- 盡量避免使用null()
索引類型
- btree索引
- 將節點用樹進行索引
F18AEF581E92509B292295258BE85331.png
- 找到索引,再找到對應記錄的位置獲取詳情
- 提高排序/分組/查詢速度
- 誤區:
- where id>3 and price>100,那么在id和price都建立索引.這是錯誤的,因為索引是獨立的,這條語句只能用一個索引
- 聯合索引:左前綴索引,按索引順序(語句可替換) 使用索引
- hash索引
- 將索引hash,放入對應位置
- 范圍查找,不好使
- 排序無法優化
- 優點,復雜度理論為O(1)
- 非聚簇索引
- myisam:索引和數據是分開的
- 回行拿數據
4.聚簇索引 - innoDB:索引和數據是放在一起的
- 主鍵索引即存儲索引,又存儲數據
- 非主鍵索引的數據指向主鍵鍵索引:即先找到name,name節點存儲了id,再到id索引找到詳細數據
修復表
- 索引碎片與維護
- 在長期的數據更改過程中,索引文件和數據文件,都將產生空洞,形成碎片
- 可以通過Nop(不產生對數據實質影響的操作)來修復表:
- alter table xxx engine innodb;本來就是innodb引擎
- optimize table name 來修復表
- 把數據文件對齊,比較耗資源,不能頻繁操作,如果update 操作頻繁周/月 來修復,不頻繁則更長周期來修復
explain
字段 | 解釋 |
---|---|
id: | 該語句中查詢語句的id(因為可能是嵌套查詢) |
select_type: | 見下圖 |
table : | 查詢的表\別名 |
possible_keys: | 可能用到的key |
key: | 用到的key |
type: | 查詢的方式,非常重要,是分析"查數據過程"all/index/range/ref/const/system/null效果越來越好 |
ref: | 連接查詢是,表字段的引用關系 |
rows: | 估計要掃描的行數 |
extra: | 1. index:用到了索引覆蓋,效率非常高;2. usering where指光靠索引不能定位,還要where判斷一下;3. usering temporary用了臨時表,group by 與order by 不同列時,或group by order by別的表的列;4. usering filesort:文件排序 |
0350565611272DB6AB52F0DA38415432.png
in型子查詢陷阱
mysql的查詢優化器,針對in型查詢做了優化,被改成了exists子茶行的執行效果
改進:用鏈接查詢代替子查詢
count小技巧
表a有44555550條數據
想知道id大于1000的有多少條數據
直接select count() from a where id>1000;耗時可能有4/5s
優化策略:
select count() from a 得到總記錄數 total;
select count(*) from a<=1000得到記錄數 lt1000;
total-lt1000=總數-一小塊=剩下一大塊
union小技巧
union會排序,去重
union all 不會排序去重
limit翻頁優化
limit隨著翻頁offset的增長,越來越慢
limit 10000,5 :拿出10005行,丟掉前邊10000行,返回5行數據
改進方法
用where進行優化
select * from a where id>10000 limit 5;
這個要求數據id不能斷
思路是:將分頁只在索引葉子上進行,得到要獲取的id,然后根據id區查詢詳情:
select * from a inner join (select id from a limit 1000000,5) as b on a.id=b.id;