日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL - order by和 group by 优化初探

發布時間:2025/3/21 数据库 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL - order by和 group by 优化初探 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 生猛干貨
  • DB Version
  • Table
  • 數據量
  • 案例一 :explain select * from employees where name = 'LiLei' and position = 'dev' order by age
  • 案例二: explain select * from employees where name = 'LiLei' order by position
  • 案例三:explain select * from employees where name = 'LiLei' order by age , position
  • 案例四:explain select * from employees where name = 'LiLei' order by position , age
  • 案例五:explain select * from employees where name = 'LiLei' and age = 18 order by position , age ;
  • 案例六:explain select * from employees where name = 'LiLei' order by age asc , position desc ;
  • 案例七:explain select * from employees where name in ('HanMeiMei' , 'LiLei') order by age , position ;
  • 案例八: explain select * from employees where name > 'HanMeiMei' order by name ;
  • group by 優化
  • 小結
  • 搞定MySQL


生猛干貨

帶你搞定MySQL實戰,輕松對應海量業務處理及高并發需求,從容應對大場面試


DB Version

mysql> select version(); +-----------+ | version() | +-----------+ | 5.7.28 | +-----------+ 1 row in setmysql>

Table

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

兩個索引

  • 主鍵索引
  • 二級索引 KEY idx_name_age_position (name,age,position) USING BTREE
  • 重點就是這個二級索引 ,記號了哈。


    數據量

    mysql> select count(1) from employees ; +----------+ | count(1) | +----------+ | 100002 | +----------+ 1 row in setmysql>

    案例一 :explain select * from employees where name = ‘LiLei’ and position = ‘dev’ order by age

    explain select * from employees where name = 'LiLei' and position = 'dev' order by age ;

    先想一下這個order by 會不會走索引 ?

    會走索引

    原因呢 ?

    腦海中要有這個聯合索引在MySQL底層的B+Tree的數據結構 , 索引 排好序的數據結構。

    name = ‘LiLei’ and position = ‘dev’ order by age

    name 為 LiLei , name 確定的情況下, age 肯定是有序的 ,age 有序不能保證position 有序

    所以 這個order by age 是可以走索引的

    繼續分析下這個explain

    mysql> explain select * from employees where name = 'LiLei' and position = 'dev' order by age ; +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-----------------------+ | 1 | SIMPLE | employees | NULL | ref | idx_name_age_position | idx_name_age_position | 74 | const | 1 | 10 | Using index condition | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-----------------------+ 1 row in set

    order by 走的索引 是不會體現在key_len上的, 這個74 = 3 * 24 + 2 , 是計算的name 。 最左匹配原則 ,中間字段不能斷,因此查詢用到了name索引。

    但是 Extra直接里面可以看出來 Using index condition ,說明age索引列用在了排序過程中 。 如果沒有走索引的話,那就是 Using FileSort 了

    接下來繼續看幾個例子,加深理解,重點是腦海中的 索引B+Tree結構


    案例二: explain select * from employees where name = ‘LiLei’ order by position

    mysql> explain select * from employees where name = 'LiLei' order by position ;

    想一想,這個order by 會走索引嗎?

    我們來看下索引 KEY idx_name_age_position (name,age,position) USING BTREE

    再來看下查詢SQL

    where name = 'LiLei' order by position ;

    name = LiLei , name 值能確定下來, 符合最左匹配原則 所以查詢會走索引 , 用了聯合索引中的name字段, key len = 74 . 所以 Using index condition

    order by position , 在索引中 中間缺失了age , 用position ,跳過了age , 那索引樹能是有序的嗎? 肯定不是。。。所以 position肯定不是排好序的 , 無法走索引排序,因此 Extra信息 有 Using filesort

    來看下執行計劃

    mysql> explain select * from employees where name = 'LiLei' order by position ; +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ | 1 | SIMPLE | employees | NULL | ref | idx_name_age_position | idx_name_age_position | 74 | const | 1 | 100 | Using index condition; Using filesort | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ 1 row in setmysql>

    正如分析~

    有感覺了嗎? 再來看一個


    案例三:explain select * from employees where name = ‘LiLei’ order by age , position

    這個SQL和案例二的很相似 , 僅僅在排序的時候在前面多了一個age字段參與排序 , 那分析分析 order by 會走索引嗎

    mysql> explain select * from employees where name = 'LiLei' order by age , position ;

    時刻不要那個索引樹 ,來分析一下

    name = LiLei , name 固定,結合 建立的索引, 最左原則,所以查詢肯定會走聯合索引中的部分索引 name .

    在name都是LiLei 的情況下 , order by age , position 結合索引樹 ,age和position用于排序 也是有序的,應該不會走using filesort

    我們來看下執行計劃

    mysql> explain select * from employees where name = 'LiLei' order by age , position ; +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-----------------------+ | 1 | SIMPLE | employees | NULL | ref | idx_name_age_position | idx_name_age_position | 74 | const | 1 | 100 | Using index condition | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-----------------------+ 1 row in setmysql>

    案例四:explain select * from employees where name = ‘LiLei’ order by position , age

    再分析一個,和案例上也很像。 把 order by的排序順序 調整一下,我們來分析一下 order by會不會走索引

    explain select * from employees where name = 'LiLei' order by position , age ;

    mysql> explain select * from employees where name = 'LiLei' order by position , age ; +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ | 1 | SIMPLE | employees | NULL | ref | idx_name_age_position | idx_name_age_position | 74 | const | 1 | 100 | Using index condition; Using filesort | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ 1 row in setmysql>

    咦 , 執行計劃中有 using filesort

    為什么呢?

    看看我們二級索引的建立的字段順序 , 創建順序為name,age,position,但是排序的時候age和position顛倒位置了, 那排好序的特性肯定就無法滿足了,那你讓MySQL怎么走索引?


    案例五:explain select * from employees where name = ‘LiLei’ and age = 18 order by position , age ;

    這個order by 會走索引嗎?

    mysql> explain select * from employees where name = 'LiLei' and age = 18 order by position , age ; +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------------+------+----------+-----------------------+ | 1 | SIMPLE | employees | NULL | ref | idx_name_age_position | idx_name_age_position | 78 | const,const | 1 | 100 | Using index condition | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------------+------+----------+-----------------------+ 1 row in setmysql>

    走了dx_name_age_position 索引中的 name 和 age , order by 其實也走了索引,你看extra中并沒有 using filesort ,因為age為常量,在排序中被MySQL優化了,所以索引未顛倒,不會出現Using filesort


    案例六:explain select * from employees where name = ‘LiLei’ order by age asc , position desc ;

    mysql> explain select * from employees where name = 'LiLei' order by age asc , position desc ; +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ | 1 | SIMPLE | employees | NULL | ref | idx_name_age_position | idx_name_age_position | 74 | const | 1 | 100 | Using index condition; Using filesort | +----+-------------+-----------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+---------------------------------------+ 1 row in set

    我們可以看到雖然排序的字段列與建立索引的順序一樣, order by默認升序排列,而SQL中的 position desc變成了降序排列,導致與索引的排序方式不同,從而產生Using filesort。

    Note: Mysql8以上版本有降序索引可以支持該種查詢方式。


    案例七:explain select * from employees where name in (‘HanMeiMei’ , ‘LiLei’) order by age , position ;

    mysql> explain select * from employees where name in ('HanMeiMei' , 'LiLei') order by age , position ; +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+---------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+---------------------------------------+ | 1 | SIMPLE | employees | NULL | range | idx_name_age_position | idx_name_age_position | 74 | NULL | 2 | 100 | Using index condition; Using filesort | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+---------------------------------------+ 1 row in setmysql>

    對order by 來講 ,多個相等的條件也是 范圍查詢。 既然是范圍查詢, 可能對于每個值在索引中是有序的,但多個合并在一起,就不是有序的了,所以 using filesort .


    案例八: explain select * from employees where name > ‘HanMeiMei’ order by name ;

    mysql> explain select * from employees where name > 'HanMeiMei' order by name ; +----+-------------+-----------+------------+------+-----------------------+------+---------+------+-------+----------+-----------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+------+---------+------+-------+----------+-----------------------------+ | 1 | SIMPLE | employees | NULL | ALL | idx_name_age_position | NULL | NULL | NULL | 96845 | 50 | Using where; Using filesort | +----+-------------+-----------+------------+------+-----------------------+------+---------+------+-------+----------+-----------------------------+ 1 row in setmysql>

    MySQL自己內部有一套優化機制,且數據量不同、版本不一樣,結果也可能有差異

    一般情況下, 聯合索引第一個字段用范圍不一定會走索引 , 可以采用 覆蓋索引進行優化,避免回表帶來的性能開銷 。

    mysql> explain select namefrom employees where name > 'a' order by name ; +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+--------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+--------------------------+ | 1 | SIMPLE | employees | NULL | range | idx_name_age_position | idx_name_age_position | 74 | NULL | 48422 | 100 | Using where; Using index | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+--------------------------+ 1 row in setmysql>


    group by 優化

    • group by與order by類似,其實質是先排序后分組遵照索引創建順序的最左前綴法則

    • 對于group by的優化如果不需要排序的可以加上order by null禁止排序

    • where高于having,能寫在where中的限定條件就不要去having限定了。


    小結

    • MySQL支持兩種方式的排序filesort和index,Using index是指MySQL掃描索引本身完成排序

    • order by滿足兩種情況會使用Using index
      A: order by語句使用索引最左前列。
      B: 使用where子句與order by子句條件列組合滿足索引最左前列

    • 盡量在索引列上完成排序,遵循索引建立(索引創建的順序)時的最左前綴法則

    • 如果order by的條件不在索引列上,就會產生Using filesort

    • 能用覆蓋索引盡量用覆蓋索引


    搞定MySQL

    總結

    以上是生活随笔為你收集整理的MySQL - order by和 group by 优化初探的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。