2016-04-03 172 views
0

我正在嘗試獲取尚未訂購6個月或更長時間的客戶的列表。我有我在查詢中使用了4臺使用LEFT JOIN優化MySql查詢

  • 帳戶(ACCOUNT_ID)
  • 店(STORE_ID,ACCOUNT_ID)
  • 客戶(STORE_ID,CUSTOMER_ID)
  • 訂單(ORDER_ID,CUSTOMER_ID,STORE_ID)

客戶和訂單表格非常大,分別是3M和26M行,所以在我的查詢中使用左連接使查詢時間非常長。我相信我有索引我的表正確

這裏是我的查詢我用

SELECT cus.customer_id, MAX(o.order_date), cus.store_id, s.account_id, store_name 
FROM customers cus 
LEFT JOIN stores s ON s.store_id=cus.store_id 
LEFT JOIN orders o ON o.customer_id=cus.customer_id AND o.store_id=cus.store_id 
WHERE account_id=26 AND 
    (SELECT order_id 
     FROM orders o 
     WHERE o.customer_id=cus.customer_id 
     AND o.store_id=cus.store_id 
     AND o.order_date < CURRENT_DATE() - INTERVAL 6 MONTH 
     ORDER BY order_id DESC LIMIT 0,1) IS NOT NULL 
GROUP BY cus.customer_id, cus.client_id; 

我需要得到最後訂購日期,這就是爲什麼我加入了訂單表的原因,然而,由於客戶可以有多個訂單,它將返回多行客戶,這就是爲什麼我使用了group by子句。

如果任何人都可以幫助我的查詢。

+0

請提供'SHOW CREATE TABLE'。 –

+0

客戶是否在不同的store_id上​​最近購買了某件東西,這有沒有關係? (Ollie和我在這裏做了不同的假設。) –

+0

感謝您的回覆。客戶不能有多個store_id。 –

回答

2

開始:在此期間,讀這

SELECT customer_id, MAX(order_date) AS last_order_date 
    FROM orders 
    GROUP BY customer_id 
    HAVING last_order_date < NOW() - INTERVAL 6 MONTH; 

假設給你相關的CUSTOMER_IDS,然後轉移到

SELECT ... 
    FROM (that-select-as-a-subquery) AS old 
    JOIN other-tables-as-needed ON USING(customer_id) 

如果有必要,JOIN回到訂單以獲取更多信息。做不是嘗試獲取該子查詢中的其他列。 (這是「分組最大」問題。)

+0

我認爲我瞭解你的建議,我會通過首先獲得所有訂單,然後過濾客戶 –

+0

感謝您的建議,首先通過查找所有的訂單先找到老客戶,然後過濾來自客戶的工作表現良好。查詢花了超過5分鐘,現在我可能會考慮做一些更智能的索引。 –

+0

這個組合索引是一個很好的開始:'INDEX(customer_id,order_date)'。 –

0

您在您的orders表上使用有序和有限子查詢的策略可能是您的糟糕表現的原因。

該子查詢將生成一個虛擬表,顯示每個不同客戶的最近訂單的日期。 (我想一個不同的客戶是由customer_id, store_id這對貨幣區分的)。

    SELECT MAX(order_date) recent_order_date, 
         customer_id, store_id 
        FROM orders 
        GROUP BY customer_id, store_id 

然後,您可以使用子查詢就好像它是在查詢表

SELECT cus.customer_id, summary.recent_order_date, 
     cus.store_id, s.account_id, store_name 
    FROM customers cus 
    JOIN stores s ON s.store_id=cus.store_id 
    JOIN (
       SELECT MAX(order_date) recent_order_date, 
        customer_id, store_id 
       FROM orders 
       GROUP BY customer_id, store_id 
     ) summary ON summary.customer_id = cus.customer_id 
       AND summary.store_id = s.store_id 
WHERE summary.recent_order_date < CURRENT_DATE - INTERVAL 6 MONTH 
    AND store.account_id = 26 

該方法移動GROUP BY到內部查詢,並消除了浪費的ORDER BY ... LIMIT查詢模式。內部查詢不必爲外部查詢中的每一行重新編寫。

我不明白你爲什麼在查詢中使用了LEFT JOIN操作。

順便說一下,大多數人在他們剛剛接觸SQL時,並沒有很好的直覺判斷哪些索引是有用的,哪些不是。所以,在尋求幫助時,顯示索引總是很好的。與此

http://use-the-index-luke.com/

+0

感謝您的詳細回覆,我會讓你知道我是如何去做的。 –