2011-12-23 71 views
3

我有兩個表 - 一個叫customer_records,另一個叫customer_actions查詢效率(多選)

customer_records有以下模式:

CustomerID (auto increment, primary key) 
CustomerName 
...etc... 

customer_actions有以下模式:

ActionID (auto increment, primary key) 
CustomerID (relates to customer_records) 
ActionType 
ActionTime (UNIX time stamp that the entry was made) 
Note (TEXT type) 

用戶每次進行一個客戶記錄的操作,一個條目是customer_actions製造,並且用戶有機會輸入筆記。 ActionType可以是幾個值之一(如'指定更新'或'添加案例信息' - 只能是選項列表中的一個)。

我想要做的是顯示customer_records的記錄列表,其中最後的ActionType是一個特定的值。

到目前爲止,我已經搜查網/ SO,並想出這個怪物:

SELECT * FROM (
    SELECT * FROM (
     SELECT * FROM `customer_actions` ORDER BY `EntryID` DESC 
    ) list1 GROUP BY `CustomerID` 
) list2 WHERE `ActionType`='whatever' LIMIT 0,30 

這是偉大的 - 它列出了每個客戶ID和他們的最後一個動作。但查詢是極端緩慢的場合(注:在customer_records有近2萬條記錄)。任何人都可以提供關於如何將查詢的這個怪物排序或調整我的表以提供更快結果的任何提示?我正在使用MySQL。任何幫助真的很感激,謝謝。

編輯:爲了清楚起見,我需要查看上次操作是「無論」的客戶列表。

+0

這是否意味着如果客戶的最後一個動作(由ActionDate)是*不是*'無論'那麼該客戶不應該被列出?對於列出的客戶,您是否只想要客戶,或者他們最後的行動,還是他們所有的行爲? – MatBailie 2011-12-23 00:31:13

+0

@Dems如果客戶的最新'ActionType'不是'任何',那麼他們不應該被顯示。對於那些擁有最新'ActionType'的'無論'我都需要'customer_records'的信息 - 但這並不需要在一個查詢中全部覆蓋。 – Jonathon 2011-12-23 00:41:28

回答

5

由他們的最後一個動作篩選客戶,你可以使用相關子查詢...

SELECT 
    * 
FROM 
    customer_records 
INNER JOIN 
    customer_actions 
    ON customer_actions.CustomerID = customer_records.CustomerID 
    AND customer_actions.ActionDate = (
      SELECT 
      MAX(ActionDate) 
      FROM 
      customer_actions AS lookup 
      WHERE 
      CustomerID = customer_records.CustomerID 
     ) 
WHERE 
    customer_actions.ActionType = 'Whatever' 

您可能會發現更有效的避免相關子查詢如下...

SELECT 
    * 
FROM 
    customer_records 
INNER JOIN 
    (SELECT CustomerID, MAX(ActionDate) AS ActionDate FROM customer_actions GROUP BY CustomerID) AS last_action 
    ON customer_records.CustomerID = last_action.CustomerID 
INNER JOIN 
    customer_actions 
    ON customer_actions.CustomerID = last_action.CustomerID 
    AND customer_actions.ActionDate = last_action.ActionDate 
WHERE 
    customer_actions.ActionType = 'Whatever' 
+0

謝謝 - 第一個查詢返回了預期的結果(太棒了!),但花了* 445秒*來完成: - | !第二個查詢返回一個空集。 – Jonathon 2011-12-23 15:24:29

+0

@JonnyKeogh - 在那裏有兩個拼寫錯誤,現在已更正。 * [您是否在customer_actions(CustomerID,ActionDate)上有覆蓋索引?] * – MatBailie 2011-12-23 15:40:49

+0

工作,非常感謝! – Jonathon 2011-12-23 17:17:44

2

我不確定我是否瞭解這些要求,但它在我看來像一個JOIN就足夠了。

SELECT cr.CustomerID, cr.CustomerName, ... 
FROM customer_records cr 
     INNER JOIN customer_actions ca ON ca.CustomerID = cr.CustomerID 
WHERE `ActionType` = 'whatever' 
ORDER BY 
     ca.EntryID 

注意20.000的記錄不應該造成性能問題

+0

除了上述如果你正在重新考慮這一點,那麼我強烈建議你離開*並僅使用直接需要的列名(選擇*是一個很大的性能點擊) – Codingo 2011-12-23 00:29:02

+0

@Codingo - 你是正確的離場。該查詢已修復。 – 2011-12-23 00:30:56

+0

這個查詢選擇所有在某個時間點對他們的記錄進行過「任何」操作的客戶,但我需要查看客戶上次執行的操作對他們的記錄是「什麼」。對不起,我原來的帖子不太清楚。 – Jonathon 2011-12-23 14:43:49

2

請注意,我已經適應利芬的答案(我做了一個單獨的職位,因爲這是一個評論太長)。解決方案本身的任何功勞都歸功於他,我只是試圖向您展示一些提升性能的關鍵點。

如果速度是一個問題,然後下面應該給你提高它的一些建議:

select top 100 -- Change as required 
     cr.CustomerID , 
     cr.CustomerName, 
     cr.MoreDetail1, 
     cr.Etc 
from customer_records cr 
     inner join customer_actions ca 
      on ca.CustomerID = cr.CustomerID 
where ca.ActionType = 'x' 
order by cr.CustomerID 

的幾個注意事項:

  • 在某些情況下,我發現左外連接要快,然後內部連接 ​​- 對於這個查詢,兩者都值得衡量性能
  • 避免返回*儘可能避免返回*
  • 您不必引用'c河x',但是當你開始處理可能有多個連接的大型查詢時,這是一個很好的習慣(一旦你開始這樣做,這會很有意義的)
  • 當總是使用連接加入主鍵上
+0

'TOP 100'應該通過'Limit 100',但我猜想OP可以解決這個問題:)但是,對於* always *加入主鍵?我在這裏並不同意。如果「動作」表具有代理主鍵,則OP所需的功能仍需要加入不在主鍵中的字段。我想說的是,當MySQL使主鍵成爲聚集索引時,這樣做有實際的好處,但是如果你的邏輯意味着你不能,那麼確保你有一個合適的索引。 – MatBailie 2011-12-23 01:42:15

+0

非常有效的一點 - 現在將更多地考慮到這一點。非常感謝你。 – Codingo 2011-12-23 01:47:11

1

也許我錯過了一些東西,但是簡單的連接和where子句有什麼問題?

Select ActionType, ActionTime, Note 
FROM Customer_Records CR 
INNER JOIN customer_Actions CA 
    ON CR.CustomerID = CA.CustomerID 
Where ActionType = 'added case info' 
+0

OP需要一個客戶列表,他們在Action表中的最後一個條目是特定的操作。 「他們在動作表中的最後一個條目」是這裏缺少的部分。 * [但我確實必須檢查一下評論才能確定。] * – MatBailie 2011-12-23 01:29:38

+0

啊,是的,我重讀了OP。 「我希望能夠做的是顯示來自customer_records的最後一個ActionType是特定值的記錄列表。」這意味着我的迴應:我錯過了後來的「它列出了每個客戶ID和他們的最後一次行動」 – xQbert 2011-12-23 10:21:25