摘要:這一次,返回的結(jié)果則是李雷藍(lán)色生死戀李雷這個(gè)殺手不太冷韓梅梅冰與火之歌韓梅梅天國(guó)的階梯韓梅梅阿甘正傳安華暴走漫畫可以發(fā)現(xiàn),這一次,我們得到的結(jié)果就是按照條件參數(shù)列表李雷韓梅梅安華進(jìn)行排序后得到了。
從示例講起
我們都非常習(xí)慣通過(guò) MySQL 的 IN 函數(shù)來(lái)查詢特定集合的數(shù)據(jù),比如為了在 books 表中找出李雷、韓梅梅和安華寫的書,我們可以有如下的 SQL:
SELECT * FROM books WHERE `books`.`author` IN ("李雷","韓梅梅","安華");
注意: 可以通過(guò) SQL Fiddle 查看以上示例。
數(shù)據(jù)庫(kù)返回如下結(jié)果:
author | title |
---|---|
安華 | 暴走漫畫 |
李雷 | 藍(lán)色生死戀 |
韓梅梅 | 冰與火之歌 |
韓梅梅 | 天國(guó)的階梯 |
李雷 | 這個(gè)殺手不太冷 |
韓梅梅 | 阿甘正傳 |
雖然這樣確實(shí)能夠返回所有李雷、韓梅梅和安華寫過(guò)的書,但是返回的數(shù)據(jù)的排序方式是默認(rèn)按照數(shù)據(jù)在數(shù)據(jù)庫(kù)中的存儲(chǔ)順序,假如我們需要的返回結(jié)果是同時(shí)按照 IN 查詢條件里邊的參數(shù)順序來(lái)排序呢?這個(gè)時(shí)候我們就需要利用到 MySQL FIELD 這個(gè)函數(shù)了,F(xiàn)IELD 函數(shù)本來(lái)是 MySQL 提供用來(lái)查詢某一個(gè)字符串在給定字符串元組中的索引位置的,比如這個(gè)官方例子:
SELECT FIELD("ej", "Hej", "ej", "Heja", "hej", "foo"); # -> 2
如果將其應(yīng)用在 ORDER BY 排序條件中,就可以根據(jù)指定字段的值在給定參數(shù)列表中的索引數(shù)值,進(jìn)而將查詢結(jié)果按照參數(shù)列表排序了:
SELECT * FROM books WHERE `books`.`author` IN ("李雷","韓梅梅","安華") ORDER BY FIELD(author, "李雷","韓梅梅","安華");
注意: 可以通過(guò)SQL Fiddle查看以上示例。
這一次,返回的結(jié)果則是:
author | title |
---|---|
李雷 | 藍(lán)色生死戀 |
李雷 | 這個(gè)殺手不太冷 |
韓梅梅 | 冰與火之歌 |
韓梅梅 | 天國(guó)的階梯 |
韓梅梅 | 阿甘正傳 |
安華 | 暴走漫畫 |
可以發(fā)現(xiàn),這一次,我們得到的結(jié)果就是按照條件參數(shù)列表 "李雷","韓梅梅","安華" 進(jìn)行排序后得到了。
應(yīng)用層面的思考 1. 兼容性本文提到的 FIELD 函數(shù),畢竟只是 MySQL 數(shù)據(jù)庫(kù)內(nèi)置提供的一種函數(shù),除非你非常明確你的項(xiàng)目就是只用 MySQL 數(shù)據(jù)庫(kù),否則,你的 SQL 代碼在未來(lái)遷移到其他數(shù)據(jù)庫(kù)的過(guò)程中就會(huì)遇到語(yǔ)法兼容性問(wèn)題(只是 PostgreSQL 數(shù)據(jù)庫(kù)不支持 FIELD)。
2. 性能問(wèn)題我們都知道,數(shù)據(jù)庫(kù)在進(jìn)行 ORDER BY 排序的時(shí)候,除非它是按照某個(gè)已經(jīng)存在索引的鍵的值進(jìn)行排序,否則數(shù)據(jù)庫(kù)則需要通過(guò)計(jì)算 ORDER BY 中表達(dá)式的值并且按照查詢結(jié)果建立新的臨時(shí)表,這個(gè)過(guò)程會(huì)帶來(lái)額外的時(shí)間開(kāi)銷跟內(nèi)存開(kāi)銷,對(duì)數(shù)據(jù)庫(kù)本身就是一種性能負(fù)擔(dān)。這樣的方式在單一數(shù)據(jù)庫(kù)多個(gè)數(shù)據(jù)庫(kù)客戶端連接的時(shí)候,可能對(duì)數(shù)據(jù)庫(kù)造成太大負(fù)擔(dān)。
3. 與應(yīng)用層代碼的結(jié)合盡管使用 FIELD 函數(shù)可能帶來(lái)兼容性以及性能方面的隱患,但是 FIELD 的使用并非全是有損之處。
比如在與 Ruby 的 active_record 結(jié)合時(shí),這種通過(guò)數(shù)據(jù)庫(kù)直接完成排序等 SQL 語(yǔ)句可以方便我們構(gòu)建 ActiveRecord::Relation 對(duì)象,因?yàn)槲覀儾辉傩枰葘⒉樵兘Y(jié)果集從內(nèi)存中轉(zhuǎn)為數(shù)組排序,再進(jìn)行二次查詢,可以幫助我們減少 N+1 查詢問(wèn)題,后者也是常見(jiàn)的影響數(shù)據(jù)庫(kù)服務(wù)器性能的現(xiàn)象之一。除此之外,這樣的寫法也可以有效地幫助我們簡(jiǎn)化代碼,保持代碼簡(jiǎn)潔。
但是在不需要對(duì)數(shù)據(jù)進(jìn)行二次查詢或者查詢數(shù)據(jù)量太大的情況下,我反而建議可以通過(guò) Ruby 的 Array#sort_by 方法對(duì)數(shù)據(jù)進(jìn)行排序,這樣的話,排序的任務(wù)就轉(zhuǎn)移給了客戶端代碼,排序任務(wù)的壓力就自然分散,減輕了服務(wù)器端的壓力。
總結(jié)FIELD 函數(shù)結(jié)合 ORDER BY 可以幫助我們將查詢結(jié)果集按照參數(shù)列表順序返回;
FIELD 函數(shù)結(jié)合 ORDER BY 的方式可以幫助我們?cè)跀?shù)據(jù)庫(kù)層面完成排序,簡(jiǎn)化了業(yè)務(wù)代碼邏輯;
FIELD 函數(shù)結(jié)合 ORDER BY 可能帶來(lái) SQL 兼容性以及性能方面的問(wèn)題;
在確認(rèn)項(xiàng)目數(shù)據(jù)庫(kù)不大可能為 MySQL
之外的數(shù)據(jù)庫(kù)的前提下,查詢數(shù)據(jù)量少或者需要保持業(yè)務(wù)代碼簡(jiǎn)潔的場(chǎng)景下,我建議可以采用 FIELD 函數(shù)排序;而在數(shù)據(jù)量龐大的情況下,或者不大可能出現(xiàn)大量 N+1 查詢的情況下,我建議可以采用先在數(shù)據(jù)庫(kù)中查詢數(shù)據(jù)集(只查詢 IN 條件,不排序)再到內(nèi)存中通過(guò)業(yè)務(wù)代碼排序(比如 Ruby 的 Array#sort_by)的方式。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/17497.html
閱讀 3565·2021-10-18 13:30
閱讀 3008·2021-10-09 09:44
閱讀 2034·2019-08-30 11:26
閱讀 2424·2019-08-29 13:17
閱讀 812·2019-08-29 12:17
閱讀 2311·2019-08-26 18:42
閱讀 576·2019-08-26 13:24
閱讀 3010·2019-08-26 11:39