MySQL in 查詢,並經過 FIELD 函數按照查詢條件順序返回結果

從示例講起

咱們都很是習慣經過 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
李雷 藍色生死戀
李雷 這個殺手不太冷
韓梅梅 冰與火之歌
韓梅梅 天國的階梯
韓梅梅 阿甘正傳
安華 暴走漫畫

能夠發現,這一次,咱們獲得的結果就是按照條件參數列表 '李雷','韓梅梅','安華' 進行排序後獲得了。性能

應用層面的思考

1. 兼容性

本文提到的 FIELD 函數,畢竟只是 MySQL 數據庫內置提供的一種函數,除非你很是明確你的項目就是隻用 MySQL 數據庫,不然,你的 SQL 代碼在將來遷移到其餘數據庫的過程當中就會遇到語法兼容性問題(只是 PostgreSQL 數據庫不支持 FIELD)。code

2. 性能問題

咱們都知道,數據庫在進行 ORDER BY 排序的時候,除非它是按照某個已經存在索引的鍵的值進行排序,不然數據庫則須要經過計算 ORDER BY 中表達式的值而且按照查詢結果創建新的臨時表,這個過程會帶來額外的時間開銷跟內存開銷,對數據庫自己就是一種性能負擔。這樣的方式在單一數據庫多個數據庫客戶端鏈接的時候,可能對數據庫形成太大負擔。htm

3. 與應用層代碼的結合

儘管使用 FIELD 函數可能帶來兼容性以及性能方面的隱患,可是 FIELD 的使用並不是全是有損之處。

好比在與 Ruby 的 active_record 結合時,這種經過數據庫直接完成排序等 SQL 語句能夠方便咱們構建 ActiveRecord::Relation 對象,由於咱們再也不須要先將查詢結果集從內存中轉爲數組排序,再進行二次查詢,能夠幫助咱們減小 N+1 查詢問題,後者也是常見的影響數據庫服務器性能的現象之一。除此以外,這樣的寫法也能夠有效地幫助咱們簡化代碼,保持代碼簡潔。

可是在不須要對數據進行二次查詢或者查詢數據量太大的狀況下,我反而建議能夠經過 Ruby 的 Array#sort_by 方法對數據進行排序,這樣的話,排序的任務就轉移給了客戶端代碼,排序任務的壓力就天然分散,減輕了服務器端的壓力。

總結

  1. FIELD 函數結合 ORDER BY 能夠幫助咱們將查詢結果集按照參數列表順序返回;

  2. FIELD 函數結合 ORDER BY 的方式能夠幫助咱們在數據庫層面完成排序,簡化了業務代碼邏輯;

  3. FIELD 函數結合 ORDER BY 可能帶來 SQL 兼容性以及性能方面的問題;

  4. 在確認項目數據庫不大可能爲 MySQL
    以外的數據庫的前提下,查詢數據量少或者須要保持業務代碼簡潔的場景下,我建議能夠採用 FIELD 函數排序;而在數據量龐大的狀況下,或者不大可能出現大量 N+1 查詢的狀況下,我建議能夠採用先在數據庫中查詢數據集(只查詢 IN 條件,不排序)再到內存中經過業務代碼排序(好比 Ruby 的 Array#sort_by)的方式。

相關文章
相關標籤/搜索