2014-01-14 79 views
0

我困在一個相當複雜的查詢中。製作大型SQL查詢效率

我正在尋找一個查詢,顯示「前五名客戶」以及一些關鍵指標(包括條件計數)關於每個這些客戶。每個不同的指標都使用完全不同的連接結構。

+-----------+------------+ +-----------+------------+ +-----------+------------+ 
| customer |   | | metricn |   | | metricn_lineitem  | 
+-----------+------------+ +-----------+------------+ +-----------+------------+ 
| id  | Name  | | id  | customer_id| |id   |metricn_id | 
| 1   | Customer1 | | 1   | 1   | | 1   | 1   | 
| 2   | Customer2 | | 2   | 2   | | 2   | 1   | 
+-----------+------------+ +-----------+------------+ +-----------+------------+ 

問題是我總是想按這個客戶表分組。

我首先嚐試將所有連接放入原始查詢中,但查詢性能很差。然後我嘗試使用子查詢,但我無法讓他們按原始醫院ID進行分組。

這裏有一個簡單的查詢

SELECT 
    customer.name, 

    (SELECT COUNT(metric1_lineitem.id) 
     FROM metric1 INNER JOIN metric1_lineitem 
     ON metric1_lineitem.metric1_id = metric1.id 
     WHERE metric1.customer_id = customer_id 
    ) as metric_1, 

    (SELECT COUNT(metric2_lineitem.id) 
     FROM metric2 INNER JOIN metric2_lineitem 
     ON metric2_lineitem.metric2_id = metric2.id 
     WHERE metric2.customer_id = customer_id 
    ) as metric_2 

FROM customer 
GROUP BY customer.name 
SORT BY COUNT(metric1.id) DESC 
LIMIT 5 

有什麼建議?謝謝!

回答

1
SELECT name, metric_1, metric_2 
FROM customer AS c 
LEFT JOIN (SELECT customer_id, COUNT(*) AS metric_1 
      FROM metric1 AS m 
      INNER JOIN metric1_lineitem AS l ON m.id = l.metric1_id 
      GROUP BY customer_id) m1 
ON m1.customer_id = c.customer_id 
LEFT JOIN (SELECT customer_id, COUNT(*) AS metric_2 
      FROM metric2 AS m 
      INNER JOIN metric2_lineitem AS l ON m.id = l.metric2_id 
      GROUP BY customer_id) m1 
ON m2.customer_id = c.customer_id 
ORDER BY metric_1 DESC 
LIMIT 5 

你也應該避免使用COUNT(columnname)時,你可以使用COUNT(*)代替。前者必須測試每個值,看看它是否爲空。

+0

我不知道關於mysql,但在sql server中,這很可能會加速它,因爲相關的子查詢基本上是一行一行地處理的遊標,這是一個基於集合的解決方案。 – HLGEM

1

儘管您的數據結構可能很糟糕,但您的查詢可能並不那麼糟糕,只有兩個例外。我不認爲你需要外層的聚合。此外,where子句中的「關聯」(例如metric1.customer_id = customer_id)沒有做任何事情,因爲customer_id來自本地表。您需要metric1.customer_id = c.customer_id

SELECT c.name, 
     (SELECT COUNT(metric1_lineitem.id) 
     FROM metric1 INNER JOIN 
      metric1_lineitem 
      ON metric1_lineitem.metric1_id = metric1.id 
     WHERE metric1.customer_id = c.customer_id 
    ) as metric_1, 
     (SELECT COUNT(metric2_lineitem.id) 
     FROM metric2 INNER JOIN 
      metric2_lineitem 
      ON metric2_lineitem.metric2_id = metric2.id 
     WHERE metric2.customer_id = c.customer_id 
    ) as metric_2 
FROM customer c 
ORDER BY 1 DESC 
LIMIT 5; 

如何讓這個運行更快?一種方法是引入索引。我會推薦metric1(customer_id),metric2(customer_id),metric1_lineitem(metric1_id)metric2_lineitem(metric2_id)

這可能比聚合方法(由Barmar提出)更快,因爲MySQL對聚合效率不高。這應該允許聚合僅使用索引而不是基表進行。