咱們都很是習慣經過 MySQL 的 IN 函數來查詢特定集合的數據,好比爲了在 books 表中找出李雷、韓梅梅和安華寫的書,咱們能夠有以下的 SQL:html
SELECT * FROM books WHERE `books`.`author` IN ('李雷','韓梅梅','安華');
注意: 能夠經過 SQL Fiddle 查看以上示例。mysql
數據庫返回以下結果:sql
author | title |
---|---|
安華 | 暴走漫畫 |
李雷 | 藍色生死戀 |
韓梅梅 | 冰與火之歌 |
韓梅梅 | 天國的階梯 |
李雷 | 這個殺手不太冷 |
韓梅梅 | 阿甘正傳 |
雖然這樣確實可以返回全部李雷、韓梅梅和安華寫過的書,可是返回的數據的排序方式是默認按照數據在數據庫中的存儲順序,假如咱們須要的返回結果是同時按照 IN 查詢條件裏邊的參數順序來排序呢?這個時候咱們就須要利用到 MySQL FIELD 這個函數了,FIELD 函數原本是 MySQL 提供用來查詢某一個字符串在給定字符串元組中的索引位置的,好比這個官方例子:數據庫
SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo'); # -> 2
若是將其應用在 ORDER BY
排序條件中,就能夠根據指定字段的值在給定參數列表中的索引數值,進而將查詢結果按照參數列表排序了:數組
SELECT * FROM books WHERE `books`.`author` IN ('李雷','韓梅梅','安華') ORDER BY FIELD(author, '李雷','韓梅梅','安華');
注意: 能夠經過SQL Fiddle查看以上示例。服務器
這一次,返回的結果則是:函數
author | title |
---|---|
李雷 | 藍色生死戀 |
李雷 | 這個殺手不太冷 |
韓梅梅 | 冰與火之歌 |
韓梅梅 | 天國的階梯 |
韓梅梅 | 阿甘正傳 |
安華 | 暴走漫畫 |
能夠發現,這一次,咱們獲得的結果就是按照條件參數列表 '李雷','韓梅梅','安華'
進行排序後獲得了。性能
本文提到的 FIELD
函數,畢竟只是 MySQL 數據庫內置提供的一種函數,除非你很是明確你的項目就是隻用 MySQL 數據庫,不然,你的 SQL 代碼在將來遷移到其餘數據庫的過程當中就會遇到語法兼容性問題(只是 PostgreSQL 數據庫不支持 FIELD)。code
咱們都知道,數據庫在進行 ORDER BY
排序的時候,除非它是按照某個已經存在索引的鍵的值進行排序,不然數據庫則須要經過計算 ORDER BY
中表達式的值而且按照查詢結果創建新的臨時表,這個過程會帶來額外的時間開銷跟內存開銷,對數據庫自己就是一種性能負擔。這樣的方式在單一數據庫多個數據庫客戶端鏈接的時候,可能對數據庫形成太大負擔。htm
儘管使用 FIELD
函數可能帶來兼容性以及性能方面的隱患,可是 FIELD
的使用並不是全是有損之處。
好比在與 Ruby 的 active_record 結合時,這種經過數據庫直接完成排序等 SQL 語句能夠方便咱們構建 ActiveRecord::Relation 對象,由於咱們再也不須要先將查詢結果集從內存中轉爲數組排序,再進行二次查詢,能夠幫助咱們減小 N+1 查詢問題,後者也是常見的影響數據庫服務器性能的現象之一。除此以外,這樣的寫法也能夠有效地幫助咱們簡化代碼,保持代碼簡潔。
可是在不須要對數據進行二次查詢或者查詢數據量太大的狀況下,我反而建議能夠經過 Ruby 的 Array#sort_by
方法對數據進行排序,這樣的話,排序的任務就轉移給了客戶端代碼,排序任務的壓力就天然分散,減輕了服務器端的壓力。
FIELD 函數結合 ORDER BY 能夠幫助咱們將查詢結果集按照參數列表順序返回;
FIELD 函數結合 ORDER BY 的方式能夠幫助咱們在數據庫層面完成排序,簡化了業務代碼邏輯;
FIELD 函數結合 ORDER BY 可能帶來 SQL 兼容性以及性能方面的問題;
在確認項目數據庫不大可能爲 MySQL
以外的數據庫的前提下,查詢數據量少或者須要保持業務代碼簡潔的場景下,我建議能夠採用 FIELD 函數排序;而在數據量龐大的狀況下,或者不大可能出現大量 N+1 查詢的狀況下,我建議能夠採用先在數據庫中查詢數據集(只查詢 IN 條件,不排序)再到內存中經過業務代碼排序(好比 Ruby 的 Array#sort_by
)的方式。