MySQL中distinct語句去查詢反復記載及相干的機能評論辯論。本站提示廣大學習愛好者:(MySQL中distinct語句去查詢反復記載及相干的機能評論辯論)文章只能為提供參考,不一定能成為您想要的結果。以下是MySQL中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.custname from customers c join orders o on o.custid = c.custid join orderdetail od on od.ordid = o.ordid join articles a on a.artid = od.artid where c.city = 'GOTHAM' and a.artname = 'BATMOBILE' and o.ordered >= somefunc
個中, somefunc 是個函數,前往距今六個月前的詳細日期。留意下面用了 distinct ,由於斟酌到某個客戶可所以年夜買家,比來訂購了好幾台蝙蝠車。
暫不斟酌優化器將若何改寫此查詢,我們先看一下這段代碼的寄義。起首,來自 customers 表的數據應只保存城市名為 Gotham 的記載。接著,搜刮 orders 表,這意味著 custid 字段最好有索引,不然只要經由過程排序、歸並或掃描 orders 表樹立一個哈希表能力包管查詢速度。對 orders 表 ,還要針對定單日期停止過濾:假如優化器比擬聰慧,它會在銜接( join )前先過濾失落一些數據,從而削減前面要處置的數據量;不太聰慧的優化器則能夠會先做銜接,再作過濾,這時候在銜接中指定過濾前提利於進步機能,例如:
join orders o on o.custid = c.custid and a.ordered >= somefunc
留意,假如是:
left outer join orders o on o.custid = c.custid and 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.custname from customers c where c.city = 'GOTHAM' and exists (select null from orders o, orderdetail od, articles a where a.artname = 'BATMOBILE' and a.artid = od.artid and od.ordid = o.ordid and o.custid = c.custid and o.ordered >= somefunc )
上例的存在性測試,統一個名字能夠湧現屢次,但每一個客戶只湧現一次,不論他有若干定單。有人以為我對 ANSI SQL 語法的抉剔有點刻薄(指 " 蝙蝠車賣主 " 的例子),由於下面代碼中customers 表的位置並沒有下降。其實,症結差別在於,新查詢中 customers 表是查詢成果的獨一起源(嵌套的子查詢會擔任找出客戶子集),而先前的查詢卻用了 join 。
這個嵌套的子查詢與外層的 select 關系非常親密。如代碼第 11 行所示(粗體部門),子查詢參照了外層查詢確當前記載,是以,內層子查詢就是所謂的聯系關系子查詢( correlated subquery )。
此類子查詢有個弱點,它沒法在肯定以後客戶之前履行。假如優化器不改寫此查詢,就必需先找出每一個客戶,然後一一檢討能否知足存在性測試,當來自 Gotham 市的客戶異常少時履行效力卻是很高,不然情形會很糟(此時,優良的優化器應測驗考試其他履行查詢的方法)。
select custname from customers where city = 'GOTHAM' and custid in (select o.custid from orders o, orderdetail od, articles a where a.artname = 'BATMOBILE' and a.artid = od.artid and od.ordid = o.ordid and o.ordered >= somefunc)
在這個例子中,內層查詢不再依附外層查詢,它已釀成了非聯系關系子查詢( uncorrelated subquery ),只須履行一次。很明顯,這段代碼采取了原本的履行流程。在本節的前一個例子 中 ,必需先搜索相符所在前提的客戶(如均來自 GOTHAM ),接著順次檢討各個定單。而如今,訂購了蝙蝠車的客戶,可以經由過程內層查詢取得。
不外,假如更細心地剖析一下,前後兩個版本的代碼還有些更奧妙的差別。含聯系關系子查詢的代碼中,相當主要的是 orders 表中的 custid 字段要有索引,而這對另外一段代碼其實不主要,由於這時候要用到的索引(假如有的話)是表 customers 的主鍵索引。
你也許留意到,新版的查詢中履行了隱式的 distinct 。切實其實,因為銜接操作,子查詢能夠會前往有關一個客戶的多筆記錄。但反復項目不會有影響,由於 in 前提只檢討該項目能否湧現在子查詢前往的列表中,且 in 不在意某值在列表中湧現了一次照樣一百次。但為了分歧性,作為全體,應當對子查詢和主查詢運用雷同的規矩,也就是在子查詢中也參加存在性測試:
select custname from customers where city = 'GOTHAM' and custid in (select o.custid from orders o where o.ordered >= somefunc and exists (select null from orderdetail od, articles a where a.artname = 'BATMOBILE' and a.artid = od.artid and od.ordid = o.ordid))
或許
select custname from customers where city = 'GOTHAM' and custid in (select custid from orders where ordered >= somefunc and ordid in (select od.ordid from orderdetail od, articles a where a.artname = 'BATMOBILE' and a.artid = od.artid)
雖然嵌套變得更深、也更難明了,但子查詢內應選擇 exists 照樣 in 的選擇規矩雷同:此選擇取決於日期與商品前提的有用性。除非曩昔六個月的生意異常油膩,不然商品稱號應為最有用的過濾前提,是以子查詢頂用 in 比 exists 好,這是由於,先找出一切蝙蝠車的定單、再檢討發賣能否產生在比來六個月,比反過去操作要快。假如表 orderdetail 的 artid 字段有索引,這個辦法會更快,不然,這個聰慧奇妙的舉動就會相形見绌。
每當對年夜量記載做存在性檢討時,選擇 in 照樣 exists 須推敲。
利於多半 SQL 方言,非聯系關系子查詢可以被改寫成 from 子句中的內嵌視圖。但是,必定要記住的是, in 會隱式地剔除反復項目,當子查詢改寫為 from 子句中的內嵌視圖時,必需要顯式地清除反復項目。例如:
select custname from customers where city = 'GOTHAM' and custid in (select o.custid from orders o, (select distinct od.ordid from orderdetail od, articles a where a.artname = 'BATMOBILE' and a.artid = od.artid) x where o.ordered >= somefunc and x.ordid = o.ordid)
總結:包管 SQL 語句前往准確成果,只是樹立最好 SQL 語句的第一步。