如何優(yōu)化sql中的orderBy語(yǔ)句?下面本篇文章給大家介紹一下優(yōu)化sql中orderBy語(yǔ)句的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
程序員必備接口測(cè)試調(diào)試工具:立即使用
Apipost = Postman + Swagger + Mock + Jmeter
Api設(shè)計(jì)、調(diào)試、文檔、自動(dòng)化測(cè)試工具
后端、前端、測(cè)試,同時(shí)在線(xiàn)協(xié)作,內(nèi)容實(shí)時(shí)同步
在使用數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)查詢(xún)時(shí),難免會(huì)遇到基于某些字段對(duì)查詢(xún)的結(jié)果集進(jìn)行排序的需求。在sql中通常使用orderby語(yǔ)句來(lái)實(shí)現(xiàn)。將需要排序的字段放到 該關(guān)鍵詞后,如果有多個(gè)字段的話(huà),就用","分割。
select * from table t order by t.column1,t.column2;
上面的sql表示查詢(xún)表table中數(shù)據(jù),然后先按照column1排序,如果column1相同的話(huà),在按照column2排序,排序的方式默認(rèn)是降序。當(dāng)然排序方式也是可以指定的。在被排序字段后添加 DESC,ASE,分別表示降序和升序。
使用該orderby可以很方便的實(shí)現(xiàn)日常的排序操作。使用的多了,不知道你有沒(méi)有遇到過(guò)這種場(chǎng)景:有時(shí)候使用orderby后,sql執(zhí)行效率非常慢,有時(shí)候卻比較快,由于整天被curd纏身,也沒(méi)有時(shí)間研究,反正就是覺(jué)得很神奇。趁這個(gè)周末比較閑,就來(lái)研究下,mysql中orderby是怎么實(shí)現(xiàn)的。
為了方便描述,我們先建立一個(gè)數(shù)據(jù)表 t1,如下:
CREATE TABLE `t1` ( `id` int(11) NOT NULL not null auto_increment, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, `c` int(11) DEFAULT NULL, PRIMARY KEY (`id`) , KEY `a` (`a`) USING BTREE ) ENGINE=InnoDB;
并插入數(shù)據(jù):
insert into t1 (a,b,c) values (1,1,3); insert into t1 (a,b,c) values (1,4,5); insert into t1 (a,b,c) values (1,3,3); insert into t1 (a,b,c) values (1,3,4); insert into t1 (a,b,c) values (1,2,5); insert into t1 (a,b,c) values (1,3,6);
為了使索引生效,插入10000行 7,7,7,無(wú)關(guān)數(shù)據(jù),數(shù)據(jù)量少的情況下,會(huì)直接全表掃描
insert into t1 (a,b,c) values (7,7,7);
我們現(xiàn)在需要查找 a=1的所有記錄,然后按照b字段進(jìn)行排序。
查詢(xún)sql為
select a,b,c from t1 where a = 1 order by b limit 2;
為了防止在查詢(xún)過(guò)程中全表掃描,我們?cè)谧侄蝍上添加了索引。
首先我們先通過(guò)語(yǔ)句
explain select a,b,c from t1 where a = 1 order by b lmit 2;
查看sql的執(zhí)行計(jì)劃,如下所示:
在extra中我們可以看到出現(xiàn)了Using filesort,這個(gè)表示 該sql執(zhí)行過(guò)程中,執(zhí)行了排序操作,排序操作在 sort_buffer中完成,sort_buffer是mysql分配給每個(gè)線(xiàn)程的一個(gè)內(nèi)存緩沖區(qū),該緩沖區(qū)專(zhuān)門(mén)用來(lái)完成排序,大小默認(rèn)是1M,其大小由變量 sort_buffer_size 進(jìn)行控制。
mysql在對(duì)orderby進(jìn)行實(shí)現(xiàn)時(shí),根據(jù)放入到sort_buffer中的字段內(nèi)容不同,進(jìn)行了兩種不同實(shí)現(xiàn)方式:全字段排序和rowid排序。
全字段排序
首先我們先通過(guò)一張圖整體看一下sql執(zhí)行過(guò)程:
mysql先根據(jù)查詢(xún)條件確定需要排序的數(shù)據(jù)集,也就是表中 a=1的數(shù)據(jù)集,即主鍵id從1到6的這些記錄。
整個(gè)sql的執(zhí)行的過(guò)程如下:
1.創(chuàng)建并初始化sort_buffer,并確定需要放到該緩沖區(qū)中的字段,也就是a,b,c這三個(gè)字段。
2.從索引樹(shù)a中找到第一個(gè)滿(mǎn)足a=1的主鍵id,也就是id=1。
3.回表到id索引,取出整行數(shù)據(jù),然后從整行數(shù)據(jù)中,取出a,b,c的值,放入到sort_buffer中。
4.從索引a中按照順序找到下一個(gè)a=1的主鍵id。
5.重復(fù)步驟3和步驟4,直到獲取到最后一個(gè)a=1的記錄,也就是主鍵id=5。
6.此時(shí)滿(mǎn)足條件a=1的所有記錄的 a,b,c字段,全部讀放到了sort_buffer中,然后,對(duì)這些數(shù)據(jù)按照b的值進(jìn)行進(jìn)行排序,排序的方式是快速排序。就是那個(gè)面試經(jīng)常面到的快速排序,時(shí)間復(fù)雜度為log2n的快速排序。
7.然后從排序后的結(jié)果集中取出前2行數(shù)據(jù)。
上面是就是msql中orderby的執(zhí)行流程。因?yàn)榉湃氲絪ort_buffer中的數(shù)據(jù)是需要輸出的全部字段,所以這種排序被稱(chēng)為全排序。
看到這里不知道你是否會(huì)有疑問(wèn)?如果需要排序的數(shù)據(jù)量很大的話(huà),sort_buffer裝不下怎么辦?
的確,如果a=1的數(shù)據(jù)行特別多,且需要存放到sort_buffer中的字段比較多,可能不止a,b,c三個(gè)字段,有些業(yè)務(wù)可能需要輸出