工做中遇到的99%SQL優化,這裏都能給你解決方案(二)

-- 示例表
CREATE TABLE `employees` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
  `age` int(20) NOT NULL DEFAULT '0' COMMENT '年齡',
  `position` varchar(20) NOT NULL DEFAULT '' COMMENT '職位',
  `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '入職時間',
  PRIMARY KEY (`id`),
  KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE,
  KEY `idx_age` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=136326 DEFAULT CHARSET=utf8 COMMENT='員工表'

Order by與Group by優化

EXPLAIN select * from employees WHERE name='LiLei' and position='dev' order by age;

利用最左前綴法則:中間字段不能斷,所以查詢用到了name索引,從key_len=74也能看出,age索引列用在排序的過程當中,由於Extra字段裏沒有using filesort。web

EXPLAIN select * from employees WHERE name='LiLei'  order by position;


從explain的執行結果來看:key_len=74, 查詢使用name索引,因爲用了position進行排序,跳過了age,出現了Using filesort。sql

EXPLAIN select * from employees WHERE name='LiLei'  order by age,position;

查找只用到了name索引,age和position用於排序,無Using filesort。編程

EXPLAIN select * from employees WHERE name='LiLei'  order by position,age;

和上一個case不一樣的是,Extra中出現了Using filesort,由於索引的建立順序爲name,age,position,可是排序的時候age和position顛倒了位置。json

EXPLAIN select * from employees WHERE name='LiLei'  order by age asc, position desc;

雖然排序的字段和聯合索引順序是同樣的,且order by是默認升序,這裏position desc是降序,致使與索引的排序方式不一樣,從而產生Using filesort。Mysql8以上版本有降序索引能夠支持該種查詢方式。後端

EXPLAIN select * from employees WHERE name in('LiLei', 'zhuge')  order by age, position ;

對於排序來講,多個相等條件也是範圍查詢。緩存

EXPLAIN select * from employees WHERE name > 'a' order by name;

能夠用覆蓋索引優化session

EXPLAIN select name,age,position from employees WHERE name > 'a' order by name;

filesort排序

EXPLAIN select * from employees where name='LiLei' order by position;

查看這條sql對應trace結果(只展現排序部分):app

set session optimizer_trace="enabled=on",end_markers_in_json=on; ‐‐開啓trace
select * from employees where name = 'LiLei' order by position;
select * from information_schema.OPTIMIZER_TRACE;

{
      "join_execution": {  --sql執行階段
        "select#": 1,
        "steps": [
          {
            "filesort_information": [
              {
                "direction": "asc",
                "table": "`employees`",
                "field": "position"
              }
            ] /* filesort_information */,
            "filesort_priority_queue_optimization": {
              "usable": false,
              "cause": "not applicable (no LIMIT)"
            } /* filesort_priority_queue_optimization */,
            "filesort_execution": [
            ] /* filesort_execution */,
            "filesort_summary": {  --文件排序信息
              "rows": 1,  --預計掃描行數
              "examined_rows": 1,  --參與排序的行
              "number_of_tmp_files": 0, --使用臨時文件的個數,這個值爲0表明所有使用sort_buffer內存排序,不然使用磁盤文件排序
              "sort_buffer_size": 200704,  --排序緩存的大小
              "sort_mode": "<sort_key, additional_fields>"  --排序方式,這裏用的單路排序
            } /* filesort_summary */
          }
        ] /* steps */
      } /* join_execution */
    }

修改max_length_for_sort_data=10機器學習

set max_length_for_sort_data = 10;  --employees表全部字段長度總和確定大於10字節
select * from employees where name = 'LiLei' order by position;
select * from information_schema.OPTIMIZER_TRACE;

{
      "join_execution": {
        "select#": 1,
        "steps": [
          {
            "filesort_information": [
              {
                "direction": "asc",
                "table": "`employees`",
                "field": "position"
              }
            ] /* filesort_information */,
            "filesort_priority_queue_optimization": {
              "usable": false,
              "cause": "not applicable (no LIMIT)"
            } /* filesort_priority_queue_optimization */,
            "filesort_execution": [
            ] /* filesort_execution */,
            "filesort_summary": {
              "rows": 1,
              "examined_rows": 1,
              "number_of_tmp_files": 0,
              "sort_buffer_size": 53248,
              "sort_mode": "<sort_key, rowid>"  --排序方式爲雙路排序
            } /* filesort_summary */
          }
        ] /* steps */
      } /* join_execution */
    }

對比這兩個排序模式,單路排序會把全部的須要查詢的字段數據都放到sort_buffer中,而雙路排序只會把主鍵id和須要排序的字段放到sort_buffer中進行排序,而後再經過主鍵id 回到原表 查詢須要的字段數據。MySQL經過max_length_for_sort_data這個參數來控制排序,在不一樣場景下使用不一樣的排序模式,從而提高排序效率。編程語言

優化總結

  • Mysql支持兩種方式的排序filesort和index,using index是指Mysql掃描索引自己完成排序。index效率高,filesort效率低。
  • order by知足兩種狀況會使用using index。
    order by語句使用索引最左前列。
    使用where子句和order by子句 條件列組合知足索引最左前列。
  • 儘可能在索引列上完成排序,遵循索引創建(索引建立的順序)時候的最左前綴法則。
  • 若是order by 的條件不在索引列上,就會產生using filesort。

還沒關注個人公衆號?

  • 掃文末二維碼關注公衆號【小強的進階之路】可領取以下:
  • 學習資料: 1T視頻教程:涵蓋Javaweb先後端教學視頻、機器學習/人工智能教學視頻、Linux系統教程視頻、雅思考試視頻教程;
  • 100多本書:包含C/C++、Java、Python三門編程語言的經典必看圖書、LeetCode題解大全;
  • 軟件工具:幾乎包括你在編程道路上的可能會用到的大部分軟件;
  • 項目源碼:20個JavaWeb項目源碼。
    小強的進階之路二維碼
相關文章
相關標籤/搜索