亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > MySQL > 正文

MySQL中distinct語句去查詢重復記錄及相關的性能討論

2024-07-24 13:08:43
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了MySQL中distinct語句去查詢重復記錄及相關的性能討論,文中的觀點是在一定情況下避免在最高層查詢中使用distinct,需要的朋友可以參考下
 

在 MySQL 查詢中,可能會包含重復值。這并不成問題,不過,有時您也許希望僅僅列出不同(distinct)的值。

關鍵詞 DISTINCT 用于返回唯一不同的值,就是去重啦。用法也很簡單:

SELECT DISTINCT * FROM tableName

DISTINCT 這個關鍵字來過濾掉多余的重復記錄只保留一條。

另外,如果要對某個字段去重,可以試下:

SELECT *, COUNT(DISTINCT nowamagic) FROM table GROUP BY nowamagic

這個用法,MySQL的版本不能太低。

在編寫查詢之前,我們甚至應該對過濾條件進行排序,真正高效的條件(可能有多個,涉到同的表)是查詢的主要驅動力,低效條件只起輔助作用。那么定義高效過濾條件的準則是什呢?首先,要看過濾條件能否盡快減少必須處理的數據量。所以,我們必須倍加關注條件的寫方式。
假設有四個表: customers 、 orders 、 orderdetail 、 articles ,現在假設 SQL 要處理的問題是:找出最近六個月內居住在 Gotham 市、訂購了蝙蝠車的所有客戶。當然,編寫這個查詢有多種方法, ANSI SQL 的推崇者可能寫出下列語句:

select distinct c.custnamefrom customers cjoin orders oon o.custid = c.custidjoin orderdetail odon od.ordid = o.ordidjoin articles aon a.artid = od.artidwhere c.city = 'GOTHAM'and a.artname = 'BATMOBILE'and o.ordered >= somefunc

其中, somefunc 是個函數,返回距今六個月前的具體日期。注意上面用了 distinct ,因為考慮到某個客戶可以是大買家,最近訂購了好幾臺蝙蝠車。
暫不考慮優化器將如何改寫此查詢,我們先看一下這段代碼的含義。首先,來自 customers 表的數據應只保留城市名為 Gotham 的記錄。接著,搜索 orders 表,這意味著 custid 字段最好有索引,否則只有通過排序、合并或掃描 orders 表建立一個哈希表才能保證查詢速度。對 orders 表 ,還要針對訂單日期進行過濾:如果優化器比較聰明,它會在連接( join )前先過濾掉一些數據,從而減少后面要處理的數據量;不太聰明的優化器則可能會先做連接,再作過濾,這時在連接中指定過濾條件利于提高性能,例如:

join orders oon o.custid = c.custidand a.ordered >= somefunc

注意,如果是:

left outer join orders o ono.custid = c.custidand a.ordered >= somefunc

此處關于left表的篩選條件將失效,因為是左外連接,左表的所有列都將出現在這次連接結果集中)。
即使過濾條件與連接( join )無關,優化器也會受到過濾條件的影響。例如,若 orderdetail 的主鍵為( ordid, artid ),即 ordid 為索引的第一個屬性,那么我們可以利用索引找到與訂單相關的記錄。但如果主鍵是( artid, ordid )就太不幸了(注意,就關系理論而言 ,無論哪個版本都是完全一樣),此時的訪問效率比( ordid, artid )作為索引時要差,甚至一些數據庫產品無法使用該索引(注 3 ),唯一的希望就是在ordid 上加獨立索引了。
連接了表 orderdetail 和 orders 之后,來看 articles 表,這不會有問題,因為表 order 包括 artid 字段。最后,檢查 articles 中的值是否為 Batmobile 。查詢就這樣結束了,因為用了 distinct ,通過層層篩選的客戶名還必須要排序,以剔除重復項目。
避免在最高層使用 distinct 應該是一條基本規則 。原因在于,即使我們遺漏了連接的某個條件, distinct 也會使查詢 " 看似正確 " 地執行 —— 無可否認,發現重復數據容易,發現數據不準確很難,所以避免在最高層使用 distinct 應該是一條基本規則。
發現結果不正確更難,例如,如果恰巧有多位客戶都叫 " Wayne " , distinct 不但會剔除由同個客戶的多張訂單產生的重復項目,也會剔除由名字相同的不同客戶產生的重復項目。事實上,應該同時返回具唯一性的客戶 ID 和客戶名,以保證得到蝙蝠車買家的完整清單。
要擺脫 distinct ,可考慮以下思路:客戶在 Gohtam 市,而且滿足存在性測試,即在最近六個月訂購過蝙蝠車。注意,多數(但非全部) SQL 方言支持以下語法:

select c.custnamefrom customers cwhere c.city = 'GOTHAM'and exists (select nullfrom orders o,orderdetail od,articles awhere a.artname = 'BATMOBILE'and a.artid = od.artidand od.ordid = o.ordidand o.custid = c.custidand o.ordered >= somefunc )

上例的存在性測試,同一個名字可能出現多次,但每個客戶只出現一次,不管他有多少訂單。有人認為我對 ANSI SQL 語法的挑剔有點苛刻(指 " 蝙蝠車買主 " 的例子),因為上面代碼中customers 表的地位并沒有降低。其實,關鍵區別在于,新查詢中 customers 表是查詢結果的唯一來源(嵌套的子查詢會負責找出客戶子集),而先前的查詢卻用了 join 。
這個嵌套的子查詢與外層的 select 關系十分密切。如代碼第 11 行所示(粗體部分),子查詢參照了外層查詢的當前記錄,因此,內層子查詢就是所謂的關聯子查詢( correlated subquery )。
此類子查詢有個弱點,它無法在確定當前客戶之前執行。如果優化器不改寫此查詢,就必須先找出每個客戶,然后逐一檢查是否滿足存在性測試,當來自 Gotham 市的客戶非常少時執行效率倒是很高,否則情況會很糟(此時,優秀的優化器應嘗試其他執行查詢的方式)。

select custnamefrom customerswhere city = 'GOTHAM'and custid in(select o.custidfrom orders o,orderdetail od,articles awhere a.artname = 'BATMOBILE'and a.artid = od.artidand od.ordid = o.ordidand o.ordered >= somefunc)

在這個例子中,內層查詢不再依賴外層查詢,它已變成了非關聯子查詢( uncorrelated subquery ),只須執行一次。很顯然,這段代碼采用了原有的執行流程。在本節的前一個例子 中 ,必須先搜尋符合地點條件的客戶(如均來自 GOTHAM ),接著依次檢查各個訂單。而現在,訂購了蝙蝠車的客戶,可以通過內層查詢獲得。
不過,如果更仔細地分析一下,前后兩個版本的代碼還有些更微妙的差異。含關聯子查詢的代碼中,至關重要的是 orders 表中的 custid 字段要有索引,而這對另一段代碼并不重要,因為這時要用到的索引(如果有的話)是表 customers 的主鍵索引。
你或許注意到,新版的查詢中執行了隱式的 distinct 。的確,由于連接操作,子查詢可能會返回有關一個客戶的多條記錄。但重復項目不會有影響,因為 in 條件只檢查該項目是否出現在子查詢返回的列表中,且 in 不在乎某值在列表中出現了一次還是一百次。但為了一致性,作為整體,應該對子查詢和主查詢應用相同的規則,也就是在子查詢中也加入存在性測試:

select custnamefrom customerswhere city = 'GOTHAM'and custid in(select o.custidfrom orders owhere o.ordered >= somefuncand exists (select nullfrom orderdetail od,articles awhere a.artname = 'BATMOBILE'and a.artid = od.artidand od.ordid = o.ordid))

或者

select custnamefrom customerswhere city = 'GOTHAM'and custid in(select custidfrom orderswhere ordered >= somefuncand ordid in (select od.ordidfrom orderdetail od,articles awhere a.artname = 'BATMOBILE'and a.artid = od.artid)

盡管嵌套變得更深、也更難懂了,但子查詢內應選擇 exists 還是 in 的選擇規則相同:此選擇取決于日期與商品條件的有效性。除非過去六個月的生意非常清淡,否則商品名稱應為最有效的過濾條件,因此子查詢中用 in 比 exists 好,這是因為,先找出所有蝙蝠車的訂單、再檢查銷售是否發生在最近六個月,比反過來操作要快。如果表 orderdetail 的 artid 字段有索引,這個方法會更快,否則,這個聰明巧妙的舉措就會黯然失色。
每當對大量記錄做存在性檢查時,選擇 in 還是 exists 須斟酌。
利于多數 SQL 方言,非關聯子查詢可以被改寫成 from 子句中的內嵌視圖。然而,一定要記住的是, in 會隱式地剔除重復項目,當子查詢改寫為 from 子句中的內嵌視圖時,必須要顯式地消除重復項目。例如:

select custnamefrom customerswhere city = 'GOTHAM'and custid in(select o.custidfrom orders o,(select distinct od.ordidfrom orderdetail od,articles awhere a.artname = 'BATMOBILE'and a.artid = od.artid) xwhere o.ordered >= somefuncand x.ordid = o.ordid)

總結:保證 SQL 語句返回正確結果,只是建立最佳 SQL 語句的第一步。



注:相關教程知識閱讀請移步到MYSQL教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲三级av在线| 欧美精品国产精品日韩精品| 亚洲一区二区久久久久久| 日韩精品视频在线观看网址| 欧美黄网免费在线观看| 久久久久久亚洲精品不卡| 久久的精品视频| 欧美大片在线影院| 97视频在线观看亚洲| 2019亚洲日韩新视频| 51色欧美片视频在线观看| 久久久999国产精品| 亚洲男人的天堂网站| 日韩av手机在线观看| 亚洲va国产va天堂va久久| 国产午夜精品麻豆| 欧美激情欧美激情在线五月| 日韩av日韩在线观看| 69av在线播放| 欧美一二三视频| 深夜成人在线观看| 欧美激情在线有限公司| xxxxx91麻豆| 亚洲一区精品电影| 亚洲va国产va天堂va久久| www.日韩系列| 国产精品高清网站| 亚洲专区中文字幕| 青青青国产精品一区二区| 亚洲天堂成人在线视频| 亚洲伊人一本大道中文字幕| 亚州国产精品久久久| 欧美日本黄视频| 国产成人精品电影久久久| 欧美激情xxxx性bbbb| 亚洲精品福利在线| 在线精品播放av| 久久色在线播放| 国内精品久久久久影院 日本资源| 日韩精品在线视频观看| 国产精品va在线播放| 日韩av在线最新| www.亚洲一区| 亚洲人成网站免费播放| 精品福利在线视频| 热久久这里只有| 国产精品久久久久久久一区探花| 日韩免费在线免费观看| 国产精品日韩专区| 国产91精品不卡视频| 久久久久久国产精品| 久久人人爽国产| 日韩av电影在线网| 视频直播国产精品| 欧美激情aaaa| 狠狠久久五月精品中文字幕| 国产一区二区三区四区福利| 欧美成人免费大片| 欧美不卡视频一区发布| 久久久久久国产精品久久| 久99九色视频在线观看| 亚洲电影成人av99爱色| 国产亚洲美女久久| 久久精品亚洲精品| 久久免费成人精品视频| 久久久久久综合网天天| 中文字幕日韩有码| 亚洲人成电影网| 一区二区三区国产在线观看| 日韩av网站大全| 亚洲va电影大全| 中文字幕在线看视频国产欧美在线看完整| 国产成人精品a视频一区www| 亚洲成人黄色网| 91精品国产91久久久久福利| 久久午夜a级毛片| 亚洲成人免费在线视频| 国语自产偷拍精品视频偷| 精品呦交小u女在线| 欧美小视频在线观看| 福利微拍一区二区| 不卡av日日日| 国产精品一区二区久久精品| 亚洲а∨天堂久久精品9966| 欧美中文在线观看国产| 日韩第一页在线| 91国产美女视频| 国产精品日韩av| 成人免费激情视频| 国产精品高精视频免费| 丝袜美腿亚洲一区二区| 欧美丝袜一区二区三区| 国产成人在线亚洲欧美| 日本一区二区三区在线播放| 欧美大片va欧美在线播放| 日韩影视在线观看| 77777亚洲午夜久久多人| 亚洲区一区二区| 国产一区二区在线播放| 青青草国产精品一区二区| 亚洲男人天堂网| 成人欧美在线观看| 91po在线观看91精品国产性色| 亚洲国产中文字幕久久网| 国产在线一区二区三区| 国产精品精品久久久久久| 欧美野外wwwxxx| 亚洲剧情一区二区| 国产精品手机播放| 欧美在线视频a| 亚洲精品国产suv| 国产成人福利网站| 亚洲新声在线观看| 日韩精品丝袜在线| 精品国产精品自拍| 国产精品亚洲激情| 91在线视频导航| 欧美理论在线观看| 国产精品久久国产精品99gif| 中文字幕日韩电影| 亚洲国产成人精品久久久国产成人一区| 国产精品女视频| 国产精品av免费在线观看| 欧美在线一级va免费观看| 8090成年在线看片午夜| 久久精品2019中文字幕| www日韩中文字幕在线看| 亚洲成人精品久久| 欧美午夜视频一区二区| 久久精品一本久久99精品| 亚洲欧美国产视频| 欧美日韩一区二区三区在线免费观看| 精品小视频在线| 久久久久久网址| 国色天香2019中文字幕在线观看| 日韩av在线天堂网| 亚洲精品动漫久久久久| 中文字幕视频在线免费欧美日韩综合在线看| 中文字幕在线视频日韩| 成人妇女淫片aaaa视频| 欧美夫妻性生活xx| 久久久久久久久电影| 超碰日本道色综合久久综合| 欧美一级成年大片在线观看| 中文字幕亚洲在线| 夜夜嗨av色综合久久久综合网| 97欧美精品一区二区三区| 午夜精品一区二区三区在线视| 精品视频一区在线视频| 成人福利网站在线观看11| 91精品中文在线| 成人福利视频网| 日韩天堂在线视频| 亚洲欧美日韩直播| 国产精品电影久久久久电影网| 一区二区三区国产在线观看| 久久不射热爱视频精品| 日韩精品中文字幕有码专区| 国产精品7m视频| 成人黄色av网| 精品国产老师黑色丝袜高跟鞋| 成人精品网站在线观看| 隔壁老王国产在线精品| 国产欧美日韩高清|