2016-08-24 126 views
0

我想在兩列之一上連接兩個表。我不知道哪一個會成爲比賽。當從列表表中找到匹配行時,我需要來自feed_REIN的所有記錄和附加數據。我認爲一個左連接將工作。MySQL LEFT JOIN在兩列之一上

當我只有一個條件(即RETS.list_number = listings.CVMLS)時,它運行正常。只要我在LEFT JOIN中添加額外的OR條件,就需要永久完成查詢。

feed_RETS有大約125k條記錄和清單約有12k條記錄。

我在做什麼錯?

SELECT 

COUNT(*) 

FROM feed_RETS AS RETS LEFT JOIN listings ON listings.statusID IN (1,2,3) AND (RETS.list_number = listings.CVMLS OR RETS.list_number = listings.REIN) 

WHERE RETS.public_status NOT LIKE '%Sold%' 
+0

沒有解釋計劃,沒有模式細節,沒有統計數據,沒有示例數據和輸出:downvote。 – symcbean

回答

0

看解釋計劃來更好地瞭解or子句的查詢。這個查詢唯一可能的連接算法很可能是嵌套循環連接,這對您的表格來說效率非常低。您可以將查詢改寫爲這樣的:

SELECT 
COUNT(*) 
FROM(
(SELCT * FROM feed_RETS AS RETS LEFT JOIN listings ON statusID IN (1,2,3) AND RETS.list_number = listings.CVMLS WHERE public_status NOT LIKE '%Sold%') 
UNION 
(SELCT * FROM feed_RETS AS RETS LEFT JOIN listings ON statusID IN (1,2,3) AND RETS.list_number = listings.REIN WHERE public_status NOT LIKE '%Sold%'))T 
+0

感謝您的建議。我曾經考慮過這個問題,但希望能夠用LEFT JOIN和OR子句完成我所需要的。顯然我不瞭解效果。 – user1723974

0

試試這個:

SELECT 
COUNT(*) 
FROM feed_RETS AS RETS 
LEFT JOIN listings on 
    RETS.list_number = listings.CVMLS 
    OR RETS.list_number = listings.REIN 
WHERE public_status NOT LIKE '%Sold%' and statusID IN (1,2,3) 
0

如果您打算無論是cvmls或收服(異或)和應用程序可以確保要麼可能是真實的,但不是兩者,那麼在邏輯上的LEFT JOIN是不必要的,查詢總是會產生相同的行數。但是,如果兩者都可以在同一行相匹配,那麼請考慮是否要COUNT(*)所有可能的匹配,包括從加入的左側重複]或COUNT(DISTINCT r.list_number)唯一不同的表] :

-- Query 1 
SELECT COUNT(*) 
    FROM feed_RETS AS RETS LEFT JOIN listings 
           ON listings.statusID IN (1,2,3) 
           AND ( RETS.list_number = listings.CVMLS 
            OR RETS.list_number = listings.REIN 
            ) 
WHERE RETS.public_status NOT LIKE '%Sold%' 
; 

-- Query 2 - Is the count the same? 
SELECT COUNT(*) 
    FROM feed_RETS 
WHERE public_status NOT LIKE '%Sold%' 
; 

如果查詢2返回一個不同的計數,那麼請注意列表中有多行記錄被多次計數。如果你不想這樣做,那麼你需要一個不同的計數 - 或者可能是下面的一個改進。

如果查詢是爲了限制由這個連接所有標準返回的行,那麼你就需要一個INNER JOIN(並且爲了清楚起見可以在ON標準以及移動到WHERE條款):

SELECT COUNT(*) 
    FROM feed_RETS AS RETS INNER JOIN listings 
           ON ( RETS.list_number = listings.CVMLS 
             OR RETS.list_number = listings.REIN 
            ) 
WHERE listings.statusID IN (1,2,3) 
    AND RETS.public_status NOT LIKE '%Sold%' 
; 

您的查詢仍可能有兩個原因(盡我所能來診斷基於一般假設)慢:

  1. JOIN標準OR強制執行全表掃描,因爲優化器不知道使用哪個索引或是否使用任何索引。
  2. 通配符%在比賽串'%Sold%開始強制執行全表掃描,因爲指數的正常類型由從分欄的內容內置左到右。這樣想按字母順序排列的名單索引:如果你在一個名稱的開頭匹配(「與‘喬’開頭的名稱」),你可以用你的有序列表快速找到匹配的名稱;相反,如果你正在尋找某個名字中間的東西(「名字中帶有」nat「),那麼你的索引對你來說就沒用了。

該查詢實際上可能會更快:

SELECT SUM(CASE 
      WHEN l_cvmls.cvmls IS NOT NULL OR l_rein.REIN IS NOT NULL 
      THEN 1 
      ELSE 0 
      END 
     ) listing_count 
    FROM ( feed_RETS AS r LEFT JOIN listings l_cvmls 
           ON l_cvmls.statusID IN (1,2,3) 
           AND r.list_number = l_cvmls.CVMLS 
     ) LEFT JOIN listings l_rein ON l_rein.statusID IN (1,2,3) 
            AND r.list_number = l_rein.REIN 
WHERE r.public_status NOT LIKE '%Sold%' 
; 

如果你能避免'%Sold%'和使用'Sold%'相反,查詢可能會更快依然。

+0

'邏輯上總是相同的行數'你確定嗎? – Strawberry

+0

http://sqlfiddle.com/#!9/40880/1 – Strawberry

+0

@Strawberry好點。讓我換一個說法:「如果你打算使用cvmls OR rein(exclusive或),並且應用程序確保兩者都是真的,但不是兩者兼而有之,那麼邏輯上它總是相同的行數。然後請考慮是否要COUNT(*)[所有可能的匹配,包括來自連接左側的重複]或COUNT(DISTINCT r.list_number)[只有不同的列表]。「根據我對這類查詢的經驗,用例總是調用不同的行(即XOR)。補充邏輯! +1爲你:-) –