1,mysql索引性能優化最佳實戰
2, 使用索引查詢如何避免回表查詢
3,爲什麼查詢有時候加了索引也會失效?
4,如何使用 optimizer_trace 分析sql語句
5,order by 排序優化原則有哪些?
6 mysql排序支持2種 filesort 和index 的區別
7,Mysqlfilesort 排序底層實現原理
8, 單路與雙路(回表)排序底層原理。
9, 爲什麼阿里巴巴手冊不推薦使用存儲過程?
Using index: 查詢的列都是加上索引,不需要回表查詢。
什麼是回表查詢:
select * from table where name='bob'
底層先查詢username索引文件查找對應的username 'bob'的主鍵id
在根據主鍵id 查詢主鍵索引文件 對應行數據。
如果全表掃描查詢效率比索引 查詢要高,則使用全表掃描。
如果用name索引查找數據需要遍歷name字段聯合索引樹,然後根據遍歷出來的主鍵值去主鍵索引樹裏再去查找最終的數據,成本比全表掃描還高。
可以覆蓋索引優化,這樣系需要遍歷name字段的聯合索引樹就可以拿到所有的結果。
誤區:
1, 所有的字段加上了索引 就一定使用索引查詢
2,全表掃描查詢是否一定會比索引查詢慢。
排序的2種算法,
1, using filesort 索引失效 沒有根據索引字段排序的情況
2, using index 根據索引的字段排序
可以看到通過select出的字段是覆蓋索引,MySQL底層使用了索引優化。可以使用optimizer_trace 分析sql是否有走過索引:
optimizer_trace 分析sql 語句
如果全表查詢效率比索引要高,則使用全表掃描。
如果用name 索引查找數據需要遍歷name字段聯合索引樹,然後根據遍歷出來的主鍵值再去查找最終的數據,成本比全表掃描要高。
可以使用覆蓋索引,這樣只需要遍歷name的字段聯合索引樹就可以查找到結果:
SET optimizer_trace='enabled=on',end_markers_in_json=on;
SELECT * FROM employees WHERE name > 'mayikt' ;
SELECT * FROM information_schema.OPTIMIZER_TRACE;
查詢結果:
{
"steps": [
{
"join_preparation": { --第一階段:SQl準備階段
"select#": 1,
"steps": [
{
"expanded_query": "/* select#1 */ select `employees`.`id` AS `id`,`employees`.`name` AS `name`,`employees`.`age` AS `age`,`employees`.`position` AS `position`,`employees`.`hire_time` AS `hire_time` from `employees` where (`employees`.`name` > 'mayikt')"
}
] /* steps */
} /* join_preparation */
},
{
"join_optimization": { --第二階段:SQL優化階段
"select#": 1,
"steps": [
{
"condition_processing": { --條件處理
"condition": "WHERE",
"original_condition": "(`employees`.`name` > 'mayikt')",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "(`employees`.`name` > 'mayikt')"
},
{
"transformation": "constant_propagation",
"resulting_condition": "(`employees`.`name` > 'mayikt')"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "(`employees`.`name` > 'mayikt')"
}
] /* steps */
} /* condition_processing */
},
{
"substitute_generated_columns": {
} /* substitute_generated_columns */
},
{
"table_dependencies": [ --表依賴詳情
{
"table": "`employees`",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": [
] /* depends_on_map_bits */
}
] /* table_dependencies */
},
{
"ref_optimizer_key_uses": [
] /* ref_optimizer_key_uses */
},
{
"rows_estimation": [ --預估標的訪問成本
{
"table": "`employees`",
"range_analysis": { --全表掃描情況
"table_scan": {
"rows": 68511, --掃描行數
"cost": 13929 --查詢成本
} /* table_scan */,
"potential_range_indexes": [ --查詢可能使用的索引
{
"index": "PRIMARY", --主鍵索引
"usable": false,
"cause": "not_applicable"
},
{
"index": "idx_name_age_position", --輔助索引
"usable": true,
"key_parts": [
"name",
"age",
"position",
"id"
] /* key_parts */
}
] /* potential_range_indexes */,
"setup_range_conditions": [
] /* setup_range_conditions */,
"group_index_range": {
"chosen": false,
"cause": "not_group_by_or_distinct"
} /* group_index_range */,
"analyzing_range_alternatives": { ‐‐分析各個索引使用成本
"range_scan_alternatives": [
{
"index": "idx_name_age_position",
"ranges": [
"mayikt < name"
] /* ranges */,
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 34255, --‐‐索引掃描行數
"cost": 41107, --索引使用成本
"chosen": false, ‐‐是否選擇該索引
"cause": "cost"
}
] /* range_scan_alternatives */,
"analyzing_roworder_intersect": {
"usable": false,
"cause": "too_few_roworder_scans"
} /* analyzing_roworder_intersect */
} /* analyzing_range_alternatives */
} /* range_analysis */
}
] /* rows_estimation */
},
{
"considered_execution_plans": [
{
"plan_prefix": [
] /* plan_prefix */,
"table": "`employees`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 68511,
"access_type": "scan",
"resulting_rows": 68511,
"cost": 13927,
"chosen": true
}
] /* considered_access_paths */
} /* best_access_path */,
"condition_filtering_pct": 100,
"rows_for_plan": 68511,
"cost_for_plan": 13927,
"chosen": true
}
] /* considered_execution_plans */
},
{
"attaching_conditions_to_tables": {
"original_condition": "(`employees`.`name` > 'mayikt')",
"attached_conditions_computation": [
] /* attached_conditions_computation */,
"attached_conditions_summary": [
{
"table": "`employees`",
"attached": "(`employees`.`name` > 'mayikt')"
}
] /* attached_conditions_summary */
} /* attaching_conditions_to_tables */
},
{
"refine_plan": [
{
"table": "`employees`"
}
] /* refine_plan */
}
] /* steps */
} /* join_optimization */
},
{
"join_execution": { --第三階段:SQL執行階段
"select#": 1,
"steps": [
] /* steps */
} /* join_execution */
}
] /* steps */
}
全表掃描的成本低於索引掃描, 索引MySQL最終會選擇全表掃描。
Order by 培訓優化原則
1,.EXPLAIN SELECT * FROM employees WHERE name= 'meite' AND position ='ceo' order by age;
分析: 利用最左前綴法則: 中間字段不能斷,因此查詢到了name 索引
,從key_len=74 也能看出,age索引列用在排序過程中,因爲Extra 字段裏沒有
using filesort 是爲Using index condition
2,EXPLAIN SELECT * FROM employees WHERE name= 'meite' order by position;
從explain 的執行結果來看: key_len=74, 查詢使用了name 索引,由於
用了position 進行排序,跳過了age,出現了Using filesort
3.EXPLAIN SELECT * FROM employees WHERE name= 'meite' order by age,position;
分析:
查找只用到索引 name, age 和position 用於排序。,無Using filesort.
4.EXPLAIN SELECT * FROM employees WHERE name= 'meite' order by position,age;
分析:
在 Extra中出現 Using Filesort, 因爲age 爲常量,在排序中被優化,所以索引未顛倒,會出現Using Filesort
5.
EXPLAIN SELECT * FROM employees WHERE name= 'meite' order by age asc ,position desc ;
分析: age字段採用升序排序,position 降序排序 導致索引的排序方式不同,從而產生 Using filesort
EXPLAIN SELECT * FROM employees WHERE name in('meite','xiaowei') order by age, position;
f
分析: 對於多個排序來說,多個相等條件也是範圍查詢。
7, EXPLAIN SELECT * FROM employees WHERE name>'meite' order by name;
可以優化爲
EXPLAIN SELECT name,age,position FROM employees WHERE name>'meite' order by name;
排序優化總結
Mysql排序支持兩種filesort和index
1.這種方式在使用explain分析時顯示爲using index,不需要額外的排序, 是指mysql掃描索引本身完成排序,操作效率較高
2.通過對返回數據進行排序,即filesort,所有不通過索引直接返回排序結果的排序都是filesort排序
Filesort實現原理:
filesort通過相應的排序算法,將取得的數據在sort_buffer_size系統變量設置的內存排序區中進行排序,如果內存裝載不下,會將磁盤上的數據進行分塊,再對各個數據塊進行排序,再將各個塊合併成有序的結果集。
order by滿足兩種情況會使用Using index。
- order by語句使用索引最左前列。
- 使用where子句與order by子句條件列組合滿足索引最左前列。
3、儘量在索引列上完成排序,遵循索引建立(索引創建的順序)時的最左前綴法則。
4、如果order by的條件不在索引列上,就會產生Using filesort。
5、能用覆蓋索引儘量用覆蓋索引