2017-04-24 47 views
0

我有一些麻煩與執行自連接在一個子查詢,它需要比我想象它應該和我有一些認識問題,爲什麼更多的時間查詢。自加入重複檢測

的問題如下,業主可以有項目,但某些項目可能會出現兩次屬於不同的所有者,從每個業主,我們可能得到關於項目的信息稍有不同,或某些字段可能爲空。

這是我的數據庫的簡單版本,它不包含FK和索引,只有當他們出現存在IdOwner,IdItem和IdCategry。

業主:

+----------------+---------------+------+-----+ 
| Field   | Type   | Null | Key | 
+----------------+---------------+------+-----+ 
| IdOwner  | bigint(20) | NO | PRI | 
| IdPlace  | int(10)  | NO |  | 
| SomeDate  | datetime  | YES |  | 
+----------------+---------------+------+-----+ 

項目:

+----------------+---------------+------+-----+ 
| Field   | Type   | Null | Key | 
+----------------+---------------+------+-----+ 
| IdItem   | bigint(20) | NO | PRI | 
| IdOwner  | bigint(20) | NO | MUL | 
| IdCategory  | int(10)  | NO |  | 
| DupValue1  | varchar()  | YES |  | 
     . 
     . 
     . 
| DupValueN  | varchar()  | YES |  | 
+----------------+---------------+------+-----+ 

國家:

+----------------+---------------+------+-----+ 
| Field   | Type   | Null | Key | 
+----------------+---------------+------+-----+ 
| IdOwner  | bigint(20) | NO | PRI | 
| Country  | Varchar()  | NO | PRI | 
+----------------+---------------+------+-----+ 

DupValues 1到N是我發現的列具有最大概率是當物品重複時也是如此。

這是我目前正與查詢的簡化版本:

SELECT subquery1.IdItem, subquery2.IdItem FROM 
(SELECT i1.IdCategory, i1.IdOwner, i1.IdItem, i1.DupValue1, o1.IdSite, o1.SomeDate, COUNTRY.country 
FROM ITEMS i1 
LEFT JOIN OWNER o1 ON o1.IdOwner=i1.IdOwner 
LEFT JOIN COUNTRY ON i1.IdOwner=COUNTRY.IdOwner 
WHERE i1.IdOwner>9000000) 
as subquery1 
INNER JOIN 
(SELECT i2.IdCategory, i2.IdOwner, i2.IdItem, i2.DupValue1, o2.IdSite, o2.SomeDate, COUNTRY.country 
FROM ITEMS i2 
LEFT JOIN COUNTRY COUNTRY ON i2.IdOwner=COUNTRY.IdOwner 
LEFT JOIN OWNER o2 ON o2.IdOwner=i2.IdOwner 
WHERE i2.IdOwner>9000000) 
as subquery2 
ON subquery1.IdItem<subquery2.IdItem 
AND subquery1.IdCategory=subquery2.IdCategory 
AND subquery1.IdSite!=subquery2.IdSite AND subquery1.country=subquery2.country 
AND DATE(subquery1.SomeDate)=DATE(subquery2.SomeDate) 
AND (subquery1.DupValue1=subquery2.DupValue1 OR subquery1.DupValue1 IS NULL OR subquery2.DupValue1 IS NULL) 

還有一些更SupValue都具有相同的格式。

WHERE子句用於限制擁有者數量,因爲我仍然在測試查詢,當WHERE子句已經到位時,它將擁有者限制在約700,000行,並且擁有該行數的行數約爲30分鐘過程。

當我使用的查詢說明我得到這個:

+------+-------------+---------+--------+----------------------------------------+-------------+---------+------------------------+-------+------------------------------------+ 
| id | select_type | table | type | possible_keys       | key   | key_len | ref     | rows | Extra        | 
+------+-------------+---------+--------+----------------------------------------+-------------+---------+------------------------+-------+------------------------------------+ 
| 1 | SIMPLE  | i1  | range | PRIMARY,UnivocID,dg_owner,dg_category | UnivocID | 8  | NULL     | 19056 | Using index condition    | 
| 1 | SIMPLE  | o1  | eq_ref | PRIMARY        | PRIMARY  | 8  | i1.IdTender   |  1 |         | 
| 1 | SIMPLE  | country | ref | PRIMARY        | PRIMARY  | 8  | i1.IdTender   |  1 | Using index      | 
| 1 | SIMPLE  | i2  | ref | PRIMARY,UnivocID,dg_owner,dg_category | dg_category | 4  | i1.IdMolecule   | 657 | Using index condition; Using where | 
| 1 | SIMPLE  | o2  | eq_ref | PRIMARY        | PRIMARY  | 8  | i2.IdTender   |  1 | Using where      | 
| 1 | SIMPLE  | country | ref | PRIMARY        | PRIMARY  | 8  | i2.IdTender   |  1 | Using index      | 
+------+-------------+---------+--------+----------------------------------------+-------------+---------+------------------------+-------+------------------------------------+ 

MariaDB的版本:10.1

我的2個問題:

¿是否subquery2subquery1每一行執行和這是什麼原因造成的執行時間是長還是這ON條款,有過錯的性質是什麼?

¿可以查詢被提高,也許開溝贊成JOIN或其他運營商?

+0

您是否需要子查詢,或者是否可以直接在沒有子查詢的情況下完成(如果在完整查詢中在其中具有聚合函數,則可能需要子查詢)。 – Kickstart

+0

@Kickstart我需要子查詢,因爲我需要從3個表中的數據到1,然後我需要對結果表進行操作來檢測重複項,做內部連接是我知道這樣做的唯一方法。 –

+0

可能的問題是您正在使用LEFT OUTER JOINs,因此一些返回的字段可能爲NULL。而NULL不等於NULL(但你加入基於國家字段是相等的)。如果你的子查詢的效果超過了LEFT OUTER JOINs,但結果被處理的方式將意味着結果可能來自INNER JOINs – Kickstart

回答

0

我無法測試這是因爲沒有表格佈局或測試數據(並且您也參考了連接子句中名爲SubmissionDate的列,但該字段未從子查詢中返回),但應該避免以下情況使用子查詢。希望這將能夠更好地使用索引: -

SELECT subquery1.IdItem, subquery2.IdItem 
FROM ITEMS i1 
INNER JOIN ITEMS i2 
ON i1.IdItem < i1.IdItem AND i1.IdCategory = i1.IdCategory AND (i1.DupValue1 = i2.DupValue1 OR i1.DupValue1 IS NULL OR i2.DupValue1 IS NULL) 
INNER JOIN OWNER o1 ON o1.IdOwner = i1.IdOwner 
INNER JOIN COUNTRY c1 ON i1.IdOwner = c1.IdOwner 
INNER JOIN OWNER o2 ON o2.IdOwner = i2.IdOwner AND o1.IdSite != o2.IdSite 
INNER JOIN COUNTRY c2 ON i2.IdOwner = c2.IdOwner AND c1.country = c2.country 
WHERE i1.IdOwner > 9000000 
AND i2.IdOwner > 9000000 
+0

這不起作用,它需要更多的時間,我認爲這是因爲WHERE子句被應用在連接的末尾,所以它只是修剪輸出。 「,並且您還可以參考連接子句中名爲SubmissionDate的列」。 我的不好,它已經被修復了。 –

+0

如果您可以發佈表格佈局和一些示例數據,我可以嘗試。但是你的當前查詢將會受到影響,因爲MySQL可能很難從子查詢中提取任何索引來進行連接。如果您僅從每個子查詢返回一小部分數據,但可能不會包含大量數據,則速度會更快。 – Kickstart

0

調查或處理的DUP另一種技術是將行從每個表濟濟一堂到一個表,然後做GROUP BY該表。

CREATE TEMPORARY TABLE t 
    (SELECT stuff from one table or set of tables) 
    UNION ALL 
    (SELECT stuff from the other table or tables) 
; 
SELECT * FROM t 
    GROUP BY IdOwner, IdSite, country 
; 

如果需要,添加一個額外的列 「東西」 來區分來源:

SELECT 1 AS source, ... 

一種表現不佳的原因:

FROM (subquery1) 
JOIN (subquery2) ON ... 

沒有索引(直到至少5.6),以執行ON。所以子查詢結果被完全掃描。即使5.6,索引的創建也有一些開銷。

另一個提示,重新:AND DATE(subquery1.SomeDate)=DATE(subquery2.SomeDate):構建子查詢時計算DATE(SomeDate) - 這使它成爲一次性過程,而不是執行子表掃描時的重複過程。