最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL中如何優(yōu)化order by語句

 更新時間:2023年01月12日 14:57:11   作者:一個雙子座的Java攻城獅  
本文主要介紹了MySQL中如何優(yōu)化order by語句,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

order by 查詢語句使用也是非常頻繁,有時候數(shù)據(jù)量大了會發(fā)現(xiàn)排序查詢很慢,本文就介紹一下 MySQL 是如何進(jìn)行排序的,以及如何利用其原理來優(yōu)化 order by 語句。

建立一張表:

CREATE TABLE `cc4` (
  `id` INT(11) NOT NULL,
  `user_name` VARCHAR(16) NOT NULL,
  `job` VARCHAR(16) NOT NULL,
  `company` VARCHAR(16) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `company_index` (`company`)
) ENGINE=INNODB;

建完表之后,再創(chuàng)建一個腳本,在腳本中插入 2000 條數(shù)據(jù)到前面建好的表cc4 中:

DROP PROCEDURE IF EXISTS cc4_data;
DELIMITER ;;
CREATE PROCEDURE cc4_data()
BEGIN
  DECLARE i INT;
  DECLARE company VARCHAR(128);
  SET i=1;
  WHILE(i<=2000) DO
    IF i%6 = 0
      THEN SET company= '證券';
    ELSEIF i%6 = 1
      THEN SET company= '銀行';
    ELSEIF i%6 = 2
      THEN SET company= '保險';
    ELSEIF i%6 = 3
      THEN SET company= '科技';
    ELSEIF i%6 = 4
      THEN SET company= '金融';
    ELSE
      SET company ='傳統(tǒng)';
    END IF;
    INSERT INTO cc4 VALUES(i, CONCAT('孤狼',i), CONCAT('程序員',i),company);
    SET i=i+1;
  END WHILE;
END;;
DELIMITER ;
CALL cc4_data();

這時候我們?nèi)绻胍獙δ骋患夜纠锩娴娜税凑彰诌M(jìn)行排序,一般會這么寫:

SELECT user_name,job,company FROM cc4 WHERE company='科技' ORDER BY user_name LIMIT 1000;

這是一條非常簡單且常見的 sql 語句,但是就是這么簡單的一條 sql,它到底是如何被執(zhí)行的呢?

全字段排序法

首先我們對上面的語句執(zhí)行 explain 語句,看看是怎么執(zhí)行的:

explain SELECT user_name,job,company FROM cc4 WHERE company='科技' ORDER BY user_name LIMIT 1000;

在這里插入圖片描述

可以看到,在最后一列 Extra 中顯示 Using filesort,也就是說用到了文件排序,這個文件排序是如何執(zhí)行的呢?

大概畫出如下一個草圖表示表 cc4 中的索引示意圖:

在這里插入圖片描述

上圖中顯示 company 字段為普通索引,再加上主鍵索引,這張表一共有兩個索引,所以這條語句是這么執(zhí)行的:

  • 初始化 sort_buffer,并確定好需要放入 user_name ,job,company 這三個字段。
  • 從 company 索引中找到第一個滿足 company='科技’ 條件的主鍵 id,也就是上圖中的 ID-3。
  • 然后執(zhí)行回表操作,根據(jù) id 值到主鍵索引中取出整行,然后取出 user_name ,job,company 三個字段的值,并存入sort_buffer 中。
  • 從 company 索引中取下一個滿足條件記錄的主鍵 id,重復(fù)步驟 3 。
  • 繼續(xù)重復(fù) 步驟 4 和 3,直到 company 的值不滿足查詢條件為止。
  • 對 sort_buffer 中的數(shù)據(jù)按照字段 user_name 做快速排序,最后按照排序結(jié)果取前 1000 行返回給客戶端。

這種排序方式稱之為全字段排序法。

上面步驟中的第 6 步,排序可以在內(nèi)存中進(jìn)行,如果內(nèi)存足夠的話,而內(nèi)存是否足夠則取決于 sort_buffer_size 的值,但是我們想一下,如果排序的數(shù)據(jù)量太大,我們不可能提供足夠的內(nèi)存,那么這時候就不得不使用磁盤的臨時文件來進(jìn)行排序。

那么我們?nèi)绾沃喇?dāng)前的排序語句是使用文件完成排序還是使用內(nèi)存來完成排序呢?

接下來我們執(zhí)行下面兩句話:

SET optimizer_trace='enabled=on';-- 打開optimizer_trace,只對本線程有效
SELECT user_name,job,company FROM cc4 WHERE company='科技' ORDER BY user_name LIMIT 1000;
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`\G -- 查看 OPTIMIZER_TRACE 輸出

最后這條查詢語句會返回非常多的信息,包括了具體的查詢步驟,我們看到最后的 filesort_summary:

在這里插入圖片描述

這里面有幾個信息比較關(guān)鍵:

  • memory_available:表示當(dāng)前可以用于排序的內(nèi)存
  • num_rows_found:表示有多少條數(shù)據(jù)參與排序。
  • num_initial_chunks_spilled_to_disk:表示產(chǎn)生了多少個臨時文件用于排序,0表示當(dāng)前是全部采用內(nèi)存排序,這里為什么會產(chǎn)生多個文件的原因是當(dāng)數(shù)據(jù)量過大時,MySQL會分散到多個文件進(jìn)行處理,最后通過歸并排序算法來完成完整的排序。
  • sort_mode:最后這一列代表當(dāng)前排序模式,packed_additional_fields代表的就是采用了全字段排序法,而且啟用了 pack。

接下來我們把默認(rèn)的排序內(nèi)存改小一點:

SET sort_buffer_size=32768; -- 8.0 版本最小值,無法設(shè)置成更小,不同版本之間有差異
show variables like 'sort_buffer_size';

執(zhí)行之后可以看到排序大小已經(jīng)被修改為 32k:

在這里插入圖片描述

接下來我們再來執(zhí)行排序查詢跟蹤

SELECT user_name,job,company FROM cc4 WHERE company='科技' ORDER BY user_name LIMIT 1000;
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`\G -- 查看 OPTIMIZER_TRACE 輸出

這時候會發(fā)現(xiàn)這時候使用到了 6 個臨時文件進(jìn)行排序:

在這里插入圖片描述

主鍵排序法

在前面的全字段排序法中其實有些浪費,因為排序只用到了 user_name 字段,而我們卻同時查詢了其他字段,這些字段查詢出來都是會占用空間的,尤其是當(dāng)查詢的字段很多,或者有些字段又特別長的時候,會占用很大空間,導(dǎo)致不得不使用文件排序,而由于字段多又長,就會造成文件個數(shù)增多,從而導(dǎo)致排序性能會更差。

上面的查詢語句中,我們有沒有辦法不把一些無用的字段也放到 sort_buffer 中呢?

在 MySQL 中提供了一個字段 max_length_for_sort_data,默認(rèn)是 4096

show variables like 'max_length_for_sort_data';

這個字段是控制用于排序的行數(shù)據(jù)的長度的一個參數(shù)。如果用于排序的單行數(shù)據(jù)長度超過這個值,MySQL 就認(rèn)為單行數(shù)據(jù)太大了,要換一個算法,采用 rowid 算法。

采用 rowid 算法的步驟如下:

  • 初始化 sort_buffer,并確定好需要放入 user_name ,id 這兩個字段。
  • 從 company 索引中找到第一個滿足 company='科技’ 條件的主鍵 id,也就是上圖中的 ID-3。
  • 然后執(zhí)行回表操作,根據(jù) id 值到主鍵索引中查找出整行數(shù)據(jù),然后取出 user_name ,id 這兩個字段的值,并存入sort_buffer 中。
  • 從 company 索引中取下一個滿足條件記錄的主鍵 id,重復(fù)步驟 3 。
  • 繼續(xù)重復(fù) 步驟 4 和 3,直到 company 的值不滿足查詢條件為止。
  • 對 sort_buffer 中的數(shù)據(jù)按照字段 user_name 做快速排序。
  • 遍歷排序結(jié)果,取前 1000 行數(shù)據(jù),并根據(jù)主鍵 id 進(jìn)行回表查詢,取出 user_name,job 和 company三個字段返回給客戶端。

這種排序方式對比前面一種全字段排序,我們發(fā)現(xiàn)存的數(shù)據(jù)更少了,所以需要的內(nèi)存空間更少,但是又有一個更大的問題就是這里需要進(jìn)行兩次回表操作,當(dāng)數(shù)據(jù)量過大,這也會造成性能影響。

所以我們再結(jié)合前面學(xué)習(xí)的知識,如果排序的時候可以采用覆蓋索引,那么就不需要進(jìn)行回表操作,從而大幅度提升性能,這也是覆蓋索引的威力。

如何避免 filesort

首先我們看下面一個例子,執(zhí)行以下語句:

DROP INDEX company_index ON cc4;-- 刪除索引
CREATE INDEX company_user_index ON cc4 (company,user_name);-- 創(chuàng)建聯(lián)合索引
explain SELECT user_name,job,company FROM cc4 WHERE company='科技' ORDER BY user_name LIMIT 1000;

執(zhí)行結(jié)果如下:

在這里插入圖片描述

可以看到,這次就沒有用到 filesort 了,這是為什么呢?

因為我們創(chuàng)建了一個聯(lián)合索引,而 MySQL 中的 B+ 樹索引是天然有序的,所以當(dāng)指定了 company,按順序找到的數(shù)據(jù),就是按照 user_name 進(jìn)行的排序,也就不需要再執(zhí)行一次排序操作了。

到此這篇關(guān)于MySQL中如何優(yōu)化order by語句的文章就介紹到這了,更多相關(guān)MySQL優(yōu)化order by內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • window10下mysql 8.0.20 安裝配置方法圖文教程

    window10下mysql 8.0.20 安裝配置方法圖文教程

    這篇文章主要為大家詳細(xì)介紹了window10下mysql 8.0.20 安裝配置方法圖文教程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • 一文搞懂mysql如何處理json格式的字段(解析json數(shù)據(jù))

    一文搞懂mysql如何處理json格式的字段(解析json數(shù)據(jù))

    這篇文章主要給大家介紹了關(guān)于mysql如何處理json格式的字段的相關(guān)資料,MySQL中的JSON類型是一種數(shù)據(jù)類型,用于存儲和處理JSON(JavaScript Object Notation)格式的數(shù)據(jù),需要的朋友可以參考下
    2023-12-12
  • MySQL數(shù)據(jù)庫數(shù)據(jù)視圖

    MySQL數(shù)據(jù)庫數(shù)據(jù)視圖

    這篇文章主要介紹了MySQL數(shù)據(jù)庫數(shù)據(jù)視圖,視圖是原始數(shù)據(jù)庫數(shù)據(jù)的一種變換,是查看表中數(shù)據(jù)的另外一種方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-08-08
  • Mysql中的join操作

    Mysql中的join操作

    這篇文章主要介紹了Mysql join操作的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • mysql中整數(shù)數(shù)據(jù)類型tinyint詳解

    mysql中整數(shù)數(shù)據(jù)類型tinyint詳解

    大家好,本篇文章主要講的是mysql中整數(shù)數(shù)據(jù)類型tinyint詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • MySQL窗口函數(shù)OVER()用法及說明

    MySQL窗口函數(shù)OVER()用法及說明

    這篇文章主要介紹了MySQL窗口函數(shù)OVER()用法及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • MySql利用父id遞歸向下查詢子節(jié)點的方法實例

    MySql利用父id遞歸向下查詢子節(jié)點的方法實例

    項目中遇到一個需求,要求查處菜單節(jié)點的所有節(jié)點,在網(wǎng)上查了一下,大多數(shù)的方法用到了存儲過程,由于線上環(huán)境不能隨便添加存儲過程,所以自己寫一個,這篇文章主要給大家介紹了關(guān)于MySql利用父id遞歸向下查詢子節(jié)點的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • MySQL中UPDATE JOIN語句的使用詳細(xì)

    MySQL中UPDATE JOIN語句的使用詳細(xì)

    UPDATE JOIN是MySQL中一種結(jié)合UPDATE語句和JOIN操作的技術(shù),本文主要介紹了MySQL中UPDATE JOIN語句的使用詳細(xì),具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • MySQL5.7的安裝與配置詳細(xì)操作步驟

    MySQL5.7的安裝與配置詳細(xì)操作步驟

    本文分步驟詳細(xì)給大家介紹了MySQL5.7的安裝與配置詳細(xì)操作方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-02-02
  • 通過實例認(rèn)識MySQL中前綴索引的用法

    通過實例認(rèn)識MySQL中前綴索引的用法

    這篇文章主要通過實例來介紹MySQL中的前綴索引,包括前綴在實際使用中需要考慮到的長度問題等,需要的朋友可以參考下
    2015-05-05

最新評論

新邵县| 广昌县| 黔江区| 通渭县| 上思县| 西贡区| 永济市| 樟树市| 西林县| 石棉县| 梅州市| 汶上县| 桓台县| 新昌县| 大庆市| 石家庄市| 临沂市| 土默特右旗| 将乐县| 鄱阳县| 松桃| 陇南市| 仙居县| 突泉县| 铜川市| 鹰潭市| 墨玉县| 宁阳县| 普格县| 锡林浩特市| 靖远县| 苍梧县| 宜丰县| 思南县| 故城县| 抚松县| 博罗县| 安乡县| 崇仁县| 肥西县| 柯坪县|