<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SQL 查詢并不是從 SELECT 開(kāi)始的

          共 3751字,需瀏覽 8分鐘

           ·

          2021-07-16 16:30

          原文地址:SQL queries don't start with SELECT

          原文作者:Julia Evans(已授權(quán))

          譯者 & 校正:HelloGitHub-小熊熊 & 鹵蛋

          日常使用中寫(xiě) SQL 查詢命令都是以 SELECT 開(kāi)始的(注意:本文僅探討 SELECT 查詢,不涵蓋 insert 或其他 SQL 命令)。

          昨天我想到一個(gè)問(wèn)題:可以用 WHERE、HAVING 或者其他方式來(lái)過(guò)濾窗口函數(shù)執(zhí)行結(jié)果嗎?

          經(jīng)過(guò)一番探索,我得出的最終結(jié)論是否定的,因?yàn)榇翱诤瘮?shù)必須在 WHERE 和 GROUP BY 之后才能運(yùn)行。但是,這也延伸到了一個(gè)更大的問(wèn)題——SQL 查詢的執(zhí)行順序是怎么樣的呢?

          SQL 查詢執(zhí)行順序

          我專門(mén)查了一下文檔 SQL 查詢執(zhí)行順序如下:

          如果不喜歡以上五彩斑斕的圖片形式,也可以看下面的文字:

          1. FROM/JOIN/ON
          2. WHERE
          3. GROUP BY
          4. HAVING
          5. SELECT(窗口函數(shù)即在此步驟執(zhí)行)
          6. ORDER BY
          7. LIMIT

          上圖可以解答你的如下疑惑:

          上圖是 SQL 查詢的語(yǔ)義說(shuō)明。看懂這張圖,便能迅速判斷一個(gè)給定的 SQL 查詢將會(huì)返回什么結(jié)果,也可以輕松解答如下疑問(wèn):

          • 可以對(duì) GROUP BY 的結(jié)果進(jìn)行WHERE 篩選嗎?(不可以!因?yàn)?WHERE 在 GROUP BY 之前執(zhí)行)
          • 可以對(duì)窗口函數(shù)的執(zhí)行結(jié)果進(jìn)行過(guò)濾嗎?(不可以!因?yàn)榇翱诤瘮?shù)在 SELECT 步驟執(zhí)行,而這步是在 WHERE 和 GROUP BY 之后)
          • 可以對(duì) GROUP BY 的結(jié)果再執(zhí)行 ORDER BY 操作嗎? (可以!ORDER BY 基本上是最后一個(gè)步驟了,所以可以對(duì)任何操作的執(zhí)行結(jié)果執(zhí)行 ORDER BY)
          • LIMIT 執(zhí)行在哪個(gè)步驟? (最后一步!)

          雖然如此,但實(shí)際上數(shù)據(jù)庫(kù)引擎并非嚴(yán)格按照這個(gè)順序運(yùn)行查詢,因?yàn)樗鼈冞€會(huì)執(zhí)行一系列的優(yōu)化,以便提升查詢速度。

          所以:

          • 當(dāng)你想了解查詢語(yǔ)句的有效性,或是想搞明白為什么會(huì)返回這樣一個(gè)查詢結(jié)果時(shí),可以嘗試用該圖來(lái)解釋;

          • 但是,使用該圖是無(wú)法解釋查詢性能或索引相關(guān)問(wèn)題的,它們會(huì)涉及到更多變量,因而也更為復(fù)雜。

          一、最容易搞混的:列別名

          比如:關(guān)聯(lián)姓和名,并對(duì)其進(jìn)行分組。SQL 語(yǔ)法是允許這樣寫(xiě):

          SELECT CONCAT(first_name, ' ', last_name) AS full_name, count(*)
          FROM table
          GROUP BY full_name

          上面的查詢看起來(lái)像是在 SELECT 之后執(zhí)行 GROUP BY,但其實(shí) GROUP BY是先執(zhí)行的,因?yàn)?GROUP BY 引用了 SELECT 中的 alias

          數(shù)據(jù)庫(kù)引擎是可以將查詢重寫(xiě)為:

          SELECT CONCAT(first_name, ' ', last_name) AS full_name, count(*)
          FROM table
          GROUP BY CONCAT(first_name, ' ', last_name)

          接著,先執(zhí)行 GROUP BY 中的語(yǔ)句,再進(jìn)行 SELECT 操作,所以上面那么寫(xiě)是可行的。

          此外,數(shù)據(jù)庫(kù)引擎肯定會(huì)執(zhí)行一系列檢查,以確保在查詢開(kāi)始運(yùn)行之前,SELECTGROUP BY 中的內(nèi)容相匹配,因此在制定執(zhí)行計(jì)劃之前,它必須將查詢語(yǔ)句當(dāng)作一個(gè)整體來(lái)檢查。

          二、查詢并非嚴(yán)格按照此順序運(yùn)行(優(yōu)化)

          實(shí)際上,數(shù)據(jù)庫(kù)引擎并不是通過(guò)連接、過(guò)濾和分組來(lái)運(yùn)行查詢,因?yàn)樗鼘?shí)現(xiàn)了一系列優(yōu)化來(lái)提升查詢速度,如重新排序(只要不影響最終返回結(jié)果)。

          這里列舉一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明查詢的執(zhí)行順序是如何影響了查詢性能。

          SELECT * FROM
          owners LEFT JOIN cats ON owners.id = cats.owner
          WHERE cats.name = 'mr darcy'

          如果只需要查找 3 個(gè)名為“mr darcy”的貓,那么執(zhí)行整個(gè)左連接并匹配這兩個(gè)表中的所有行是很慢的。相反,如果先對(duì)名為“mr darcy”的貓進(jìn)行篩選再去執(zhí)行連接,則要快得多。在這種情況下,先執(zhí)行過(guò)濾不會(huì)改變查詢的結(jié)果!

          實(shí)際上,數(shù)據(jù)庫(kù)引擎還實(shí)現(xiàn)了許多其他的優(yōu)化,使得查詢語(yǔ)句以另外的順序來(lái)執(zhí)行,這里暫且不表。

          三、不一樣的查詢語(yǔ)法

          LINQ(C# 和 VB.NET 中的查詢語(yǔ)法)是按照FROM ... WHERE ... SELECT的順序來(lái)執(zhí)行查詢。以下是 LINQ 查詢的示例:

          var teenAgerStudent = from s in studentList
                                where s.Age > 12 && s.Age < 20
                                select s;

          Pandas(Python 數(shù)據(jù)統(tǒng)計(jì)分析工具)也基本上是這樣工作的,盡管有時(shí)候不需要嚴(yán)格按照下面的順序來(lái)編寫(xiě)代碼,但這樣也不失為一種好習(xí)慣:

          df = thing1.join(thing2)      # like a JOIN
          df = df[df.created_at > 1000# like a WHERE
          df = df.groupby('something', num_yes = ('yes''sum')) # like a GROUP BY
          df = df[df.num_yes > 2]       # like a HAVING, filtering on the result of a GROUP BY
          df = df[['num_yes''something1''something']] # pick the columns I want to display, like a SELECT
          df.sort_values('sometthing', ascending=True)[:30# ORDER BY and LIMIT
          df[:30]

          這并不是因?yàn)?Pandas 的強(qiáng)制規(guī)定,只是按照 JOIN/WHERE/GROUP BY/HAVING 的順序來(lái)編寫(xiě)代碼更有助于理解底層邏輯。(值得一提的是,可以在 JOIN 之前先執(zhí)行 WHERE 來(lái)提高性能,大多數(shù)數(shù)據(jù)庫(kù)引擎在實(shí)踐中也是這樣來(lái)執(zhí)行的)

          R 中的 dplyr(R 語(yǔ)言用來(lái)操作數(shù)據(jù)框的包)還允許采用不同的語(yǔ)法查詢不同的 SQL 數(shù)據(jù)庫(kù),如:Postgres、MySQL 和 SQLite。

          最后

          當(dāng)我發(fā)現(xiàn) SQL 查詢語(yǔ)句的這種執(zhí)行順序時(shí),我其實(shí)是非常驚訝的。通過(guò)探究 SQL 查詢語(yǔ)句的執(zhí)行順序,把我之前遇到的問(wèn)題搞清楚了。也希望本文能幫助到更多的人理解 SQL 的執(zhí)行順序以及如何正確編寫(xiě) SQL 查詢語(yǔ)句。

          最后,感謝作者的授權(quán):

          ??「點(diǎn)擊關(guān)注」第一時(shí)間收到更新??

          瀏覽 50
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美日韩三级片在线观看 | 免贾观看国产女人高潮 | 一级a一级a免费视频 | 性交动态图黄色视频在线观看 | 人人操人人吻人人射 |