成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

如何寫優(yōu)雅的SQL原生語(yǔ)句?

nihao / 3552人閱讀

摘要:如果應(yīng)用了,那么后面的所有步驟都只能操作的列或者是執(zhí)行聚合函數(shù)等。注意原因在于分組后最終的結(jié)果集中只包含每個(gè)組中的一行。等聚合函數(shù)聚合函數(shù)只是對(duì)分組的結(jié)果進(jìn)行一些處理,拿到某些想要的聚合值,例如求和,統(tǒng)計(jì)數(shù)量等,并不生成虛擬表。

前言:

上一篇講Mysql基本架構(gòu)時(shí),以“sql查詢語(yǔ)句在MySql架構(gòu)中具體是怎么執(zhí)行的?”進(jìn)行了全面的講解。知道了sql查詢語(yǔ)句在MySql架構(gòu)中的具體執(zhí)行流程,但是為了能夠更好更快的寫出sql語(yǔ)句,我覺(jué)得非常有必要知道sql語(yǔ)句中各子句的執(zhí)行順序??催^(guò)上一篇文章的小伙伴應(yīng)該都知道,sql語(yǔ)句最后各子句的執(zhí)行應(yīng)該是在執(zhí)行器中完成的,存儲(chǔ)引擎對(duì)執(zhí)行器提供的數(shù)據(jù)讀寫接口?,F(xiàn)在開始我們的學(xué)習(xí)

語(yǔ)句中各子句完整執(zhí)行順序概括(按照順序號(hào)執(zhí)行)

from (注:這里也包括from中的子語(yǔ)句)

join

on

where

group by(開始使用select中的別名,后面的語(yǔ)句中都可以使用)

avg,sum.... 等聚合函數(shù)

having

select

distinct

order by

limit

每個(gè)子句執(zhí)行順序分析

所有的 查詢語(yǔ)句都是從from開始執(zhí)行的,在執(zhí)行過(guò)程中,每個(gè)步驟都會(huì)為下一個(gè)步驟生成一個(gè)虛擬表,這個(gè)虛擬表將作為下一個(gè)執(zhí)行步驟的輸入。

1. from

form是一次查詢語(yǔ)句的開端。

如果是一張表,會(huì)直接操作這張表;

如果這個(gè)from后面是一個(gè)子查詢,會(huì)先執(zhí)行子查詢中的內(nèi)容,子查詢的結(jié)果也就是第一個(gè)虛擬表T1。(注意:子查詢中的執(zhí)行流程也是按照本篇文章講的順序哦)。

如果需要關(guān)聯(lián)表,使用join,請(qǐng)看2,3

2. join

如果from后面是多張表,join關(guān)聯(lián),會(huì)首先對(duì)前兩個(gè)表執(zhí)行一個(gè)笛卡爾乘積,這時(shí)候就會(huì)生成第一個(gè)虛擬表T1(注意:這里會(huì)選擇相對(duì)小的表作為基礎(chǔ)表);

3. on

對(duì)虛表T1進(jìn)行ON篩選,只有那些符合的行才會(huì)被記錄在虛表T2中。(注意,這里的這里如果還有第三個(gè)表與之關(guān)聯(lián),會(huì)用T2與第三個(gè)表進(jìn)行笛卡爾乘積生產(chǎn)T3表,繼續(xù)重復(fù)3. on步驟生成T4表,不過(guò)下面的順序講解暫時(shí)不針對(duì)這里的T3和T4,只是從一個(gè)表關(guān)聯(lián)查詢T2繼續(xù)說(shuō))

4. where

對(duì)虛擬表T2進(jìn)行WHERE條件過(guò)濾。只有符合的記錄才會(huì)被插入到虛擬表T3中。

5.group by

group by 子句將中的唯一的值組合成為一組,得到虛擬表T4。如果應(yīng)用了group by,那么后面的所有步驟都只能操作T4的列或者是執(zhí)行6.聚合函數(shù)(count、sum、avg等)。(注意:原因在于分組后最終的結(jié)果集中只包含每個(gè)組中的一行。謹(jǐn)記,不然這里會(huì)出現(xiàn)很多問(wèn)題,下面的代碼誤區(qū)會(huì)特別說(shuō)。)

6. avg,sum.... 等聚合函數(shù)

聚合函數(shù)只是對(duì)分組的結(jié)果進(jìn)行一些處理,拿到某些想要的聚合值,例如求和,統(tǒng)計(jì)數(shù)量等,并不生成虛擬表。

7. having

應(yīng)用having篩選器,生成T5。HAVING子句主要和GROUP BY子句配合使用,having篩選器是第一個(gè)也是為唯一一個(gè)應(yīng)用到已分組數(shù)據(jù)的篩選器。

8. select

執(zhí)行select操作,選擇指定的列,插入到虛擬表T6中。

9. distinct

對(duì)T6中的記錄進(jìn)行去重。移除相同的行,產(chǎn)生虛擬表T7.(注意:事實(shí)上如果應(yīng)用了group by子句那么distinct是多余的,原因同樣在于,分組的時(shí)候是將列中唯一的值分成一組,同時(shí)只為每一組返回一行記錄,那么所以的記錄都將是不相同的。 )

10. order by

應(yīng)用order by子句。按照order_by_condition排序T7,此時(shí)返回的一個(gè)游標(biāo),而不是虛擬表。sql是基于集合的理論的,集合不會(huì)預(yù)先對(duì)他的行排序,它只是成員的邏輯集合,成員的順序是無(wú)關(guān)緊要的。對(duì)表進(jìn)行排序的查詢可以返回一個(gè)對(duì)象,這個(gè)對(duì)象包含特定的物理順序的邏輯組織。這個(gè)對(duì)象就叫游標(biāo)。
oder by的幾點(diǎn)說(shuō)明

因?yàn)閛rder by返回值是游標(biāo),那么使用order by 子句查詢不能應(yīng)用于表表達(dá)式。

order by排序是很需要成本的,除非你必須要排序,否則最好不要指定order by,

order by的兩個(gè)參數(shù) asc(升序排列) desc(降序排列)

11. limit

取出指定行的記錄,產(chǎn)生虛擬表T9, 并將結(jié)果返回。

limit后面的參數(shù)可以是 一個(gè)limit m ,也可以是limit m n,表示從第m條到第n條數(shù)據(jù)。

(注意:很多開發(fā)人員喜歡使用該語(yǔ)句來(lái)解決分頁(yè)問(wèn)題。對(duì)于小數(shù)據(jù),使用LIMIT子句沒(méi)有任何問(wèn)題,當(dāng)數(shù)據(jù)量非常大的時(shí)候,使用LIMIT n, m是非常低效的。因?yàn)長(zhǎng)IMIT的機(jī)制是每次都是從頭開始掃描,如果需要從第60萬(wàn)行開始,讀取3條數(shù)據(jù),就需要先掃描定位到60萬(wàn)行,然后再進(jìn)行讀取,而掃描的過(guò)程是一個(gè)非常低效的過(guò)程。所以,對(duì)于大數(shù)據(jù)處理時(shí),是非常有必要在應(yīng)用層建立一定的緩存機(jī)制)

開發(fā)某需求寫的一段sql
SELECT `userspk`.`avatar` AS `user_avatar`, 
`a`.`user_id`, 
`a`.`answer_record`, 
 MAX(`score`) AS `score`
FROM (select * from pkrecord  order by score desc) as a 
INNER JOIN `userspk` AS `userspk` 
ON `a`.`user_id` = `userspk`.`user_id`
WHERE `a`.`status` = 1 
AND `a`.`user_id` != "m_6da5d9e0-4629-11e9-b5f7-694ced396953" 
GROUP BY `user_id`
ORDER BY `a`.`score` DESC 
LIMIT 9;

查詢結(jié)果:

先簡(jiǎn)要說(shuō)一下我要查詢的內(nèi)容:

想要查詢pk記錄表中分?jǐn)?shù)最高的9個(gè)用戶記錄和他們的頭像。

通過(guò)這段sql實(shí)際想一遍sql各字句的執(zhí)行順序

pk記錄表的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì),每個(gè)用戶每天每個(gè)館下可能會(huì)有多條記錄,所以需要進(jìn)行分組,并且查詢結(jié)果只想拿到每個(gè)分組內(nèi)最高的那條記錄

這段sql的一些說(shuō)明:

可能有些同學(xué)會(huì)認(rèn)為子查詢沒(méi)有必要

直接查詢pk記錄表就可以,但是并不能拿到預(yù)期的結(jié)果,因?yàn)?strong>分組后的每個(gè)組結(jié)果是不進(jìn)行排序的,而且max拿到的最高分?jǐn)?shù)肯定是對(duì)應(yīng)的該分組下最高分?jǐn)?shù),但是其它記錄可能就不是最高分?jǐn)?shù)對(duì)應(yīng)的那條記錄。所以子查詢非常有必要,它能夠?qū)υ嫉臄?shù)據(jù)首先進(jìn)行排序,分?jǐn)?shù)最高的那條就是第一條對(duì)應(yīng)的第一條記錄。

看一下代碼和執(zhí)行結(jié)果與帶有子查詢的進(jìn)行比較,就能理解我上面說(shuō)的一段話:

//不使用子查詢
SELECT `userspk`.`avatar` AS `user_avatar`, 
`pkrecord`.`user_id`, 
`pkrecord`.`answer_record`, 
`pkrecord`.`id`, 
 MAX(`score`) AS `score`
FROM pkrecord
INNER JOIN `userspk` AS `userspk` 
ON `pkrecord`.`user_id` = `userspk`.`user_id`
WHERE `pkrecord`.`status` = 1 
AND `pkrecord`.`user_id` != "m_6da5d9e0-4629-11e9-b5f7-694ced396953" 
GROUP BY `user_id`
ORDER BY `pkrecord`.`score` DESC 
LIMIT 9;

查詢結(jié)果

在子查詢中對(duì)數(shù)據(jù)已經(jīng)進(jìn)行排序后,外層排序方式如果和子查詢排序分?jǐn)?shù)相同,都是分?jǐn)?shù)倒序,外層的排序可以去掉,沒(méi)有必要寫兩遍。

sql語(yǔ)句中的別名 別名在哪些情況使用

在 SQL 語(yǔ)句中,可以為表名稱及字段(列)名稱指定別名

表名稱指定別名

同時(shí)查詢兩張表的數(shù)據(jù)的時(shí)候:
未設(shè)置別名前:

SELECT article.title,article.content,user.username FROM article, user

WHERE article.aid=1 AND article.uid=user.uid

設(shè)置別名后:

SELECT a.title,a.content,u.username FROM article AS a, user AS u where a.aid=1 and a.uid=u.uid

好處:使用表別名查詢,可以使 SQL 變得簡(jiǎn)潔而更易書寫和閱讀,尤其在 SQL 比較復(fù)雜的情況下

查詢字段指定別名

查詢一張表,直接對(duì)查詢字段設(shè)置別名

SELECT username AS name,email FROM user

查詢兩張表

好處:字段別名一個(gè)明顯的效果是可以自定義查詢數(shù)據(jù)返回的字段名;當(dāng)兩張表有相同的字段需要都被查詢出,使用別名可以完美的進(jìn)行區(qū)分,避免沖突

SELECT a.title AS atitle,u.username,u.title AS utitle FROM article AS a, user AS u where a.uid=u.uid

關(guān)聯(lián)查詢時(shí)候,關(guān)聯(lián)表自身的時(shí)候,一些分類表,必須使用別名。

別名也可以在group by與having的時(shí)候都可使用

別名可以在order by排序的時(shí)候被使用

查看上面一段sql

delete , update MySQL都可以使用別名,別名在多表(級(jí)聯(lián))刪除尤為有用

delete t1,t2 from t_a t1 , t_b t2 where t1.id = t2.id

子查詢結(jié)果需要使用別名

查看上面一段sql

別名使用注意事項(xiàng)

雖然定義字段別名的 AS 關(guān)鍵字可以省略,但是在使用別名時(shí)候,建議不要省略 AS 關(guān)鍵字

書寫sql語(yǔ)句的注意事項(xiàng) 書寫規(guī)范上的注意

字符串類型的要加單引號(hào)

select后面的每個(gè)字段要用逗號(hào)分隔,但是最后連著from的字段不要加逗號(hào)

使用子查詢創(chuàng)建臨時(shí)表的時(shí)候要使用別名,否則會(huì)報(bào)錯(cuò)。

為了增強(qiáng)性能的注意

不要使select * from ……返回所有列,只檢索需要的列,可避免后續(xù)因表結(jié)構(gòu)變化導(dǎo)致的不必要的程序修改,還可降低額外消耗的資源

不要檢索已知的列

select  user_id,name from User where user_id = ‘10000050’

使用可參數(shù)化的搜索條件,如=, >, >=, <, <=, between, in, is null以及like ‘%’;盡量不要使用非參數(shù)化的負(fù)向查詢,這將導(dǎo)致無(wú)法使用索引,如<>, !=, !>, !<, not in, not like, not exists, not between, is not null, like ‘%

當(dāng)需要驗(yàn)證是否有符合條件的記錄時(shí),使用exists,不要使用count(*),前者在第一個(gè)匹配記錄處返回,后者需要遍歷所有匹配記錄

Where子句中列的順序與需使用的索引順序保持一致,不是所有數(shù)據(jù)庫(kù)的優(yōu)化器都能對(duì)此順序進(jìn)行優(yōu)化,保持良好編程習(xí)慣(索引相關(guān))

不要在where子句中對(duì)字段進(jìn)行運(yùn)算或函數(shù)(索引相關(guān))

where amount / 2 > 100,即使amount字段有索引,也無(wú)法使用,改成where amount > 100 * 2就可使用amount列上的索引

where substring( Lastname, 1, 1) = ‘F’就無(wú)法使用Lastname列上的索引,而where Lastname like ‘F%’或者where Lastname >= ‘F’ and Lastname < ‘G’就可以

在有min、max、distinct、order by、group by操作的列上建索引,避免額外的排序開銷(索引相關(guān))

小心使用or操作,and操作中任何一個(gè)子句可使用索引都會(huì)提高查詢性能,但是or條件中任何一個(gè)不能使用索引,都將導(dǎo)致查詢性能下降,如where member_no = 1 or provider_no = 1,在member_no或provider_no任何一個(gè)字段上沒(méi)有索引,都將導(dǎo)致表掃描或聚簇索引掃描(索引相關(guān))

Between一般比in/or高效得多,如果能在between和in/or條件中選擇,那么始終選擇between條件,并用>=<=條件組合替代between子句,因?yàn)椴皇撬袛?shù)據(jù)庫(kù)的優(yōu)化器都能把between子句改寫為>=<=條件組合,如果不能改寫將導(dǎo)致無(wú)法使用索引(索引相關(guān))

調(diào)整join操作順序以使性能最優(yōu),join操作是自頂向下的,盡量把結(jié)果集小的兩個(gè)表關(guān)聯(lián)放在前面,可提高性能。(join相關(guān))

注意:索引和關(guān)聯(lián)我會(huì)多帶帶拿出來(lái)兩篇文章進(jìn)行詳細(xì)講解,在這個(gè)注意事項(xiàng)中只是簡(jiǎn)單提一下。

覺(jué)得本文對(duì)你有幫助?請(qǐng)分享給更多人

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75518.html

相關(guān)文章

  • 我就是不看好jpa

    摘要:要是緊急排查個(gè)問(wèn)題,媽蛋雖然有很多好處,比如和底層的無(wú)關(guān)。你的公司如果有,是不允許你亂用的。 知乎看到問(wèn)題《SpringBoot開發(fā)使用Mybatis還是Spring Data JPA??》,順手一答,討論激烈。我實(shí)在搞不懂spring data jpa為啥選了hibernate作為它的實(shí)現(xiàn),是Gavin King的裙帶關(guān)系么?DAO層搞來(lái)搞去,從jdbc到hibernate,從top...

    NusterCache 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<