2013-01-14 76 views
1

我很難確定如何查詢/索引數據庫。MySQL:將where子句中的日期與連接進行比較

情況很簡單。每次用戶訪問某個類別時,都會存儲他/她的訪問日期。我的目標是列出用戶最近訪問後添加元素的類別。

這裏有兩個表:

CREATE TABLE `elements` (
    `category_id` int(11) NOT NULL, 
    `element_id` int(11) NOT NULL, 
    `title` varchar(255) NOT NULL, 
    `added_date` datetime NOT NULL, 
    PRIMARY KEY (`category_id`,`element_id`), 
    KEY `index_element_id` (`element_id`) 
) 

CREATE TABLE `categories_views` (
    `member_id` int(11) NOT NULL, 
    `category_id` int(11) NOT NULL, 
    `view_date` datetime NOT NULL, 
    PRIMARY KEY (`member_id`,`category_id`), 
    KEY `index_element_id` (`category_id`) 
) 

查詢:

SELECT 
    categories_views.*, 
    elements.category_id 
FROM 
    elements 
    INNER JOIN categories_views ON (categories_views.category_id = elements.category_id) 
WHERE 
    categories_views.member_id = 1 
    AND elements.added_date > categories_views.view_date 
GROUP BY elements.category_id 

解釋:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: elements 
     type: ALL 
possible_keys: PRIMARY 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 89057 
     Extra: Using temporary; Using filesort 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: categories_views 
     type: eq_ref 
possible_keys: PRIMARY,index_element_id 
      key: PRIMARY 
     key_len: 8 
      ref: const,convert.elements.category_id 
     rows: 1 
     Extra: Using where 

隨着每個表約10萬行,查詢正在各地爲0.3s ,這對於Web上下文中的每個用戶操作都應該執行的內容來說太長了。

如果可能,我應該添加哪些索引,或者應該如何重寫此查詢以避免使用文件和臨時表?

+0

您提到表'element_views'。但它沒有加入,也沒有列在'FROM'中。你能把它從這個查詢中排除嗎? – mvp

回答

1

如果每個成員都有category_views的數量相對較少,我建議測試不同的查詢:

SELECT v.* 
    FROM categories_views v 
WHERE v.member_id = 1 
    AND EXISTS 
     (SELECT 1 
      FROM elements e 
      WHERE e.category_id = v.category_id 
      AND e.added_date > v.view_date 
     ) 

對於查詢的最佳性能,你要確保你有指標:

... ON elements (category_id, added_date) 

... ON categories_views (member_id, category_id) 

注意:它看起來像categories_views表上的主鍵可能是(member_id, category_id),這意味着一個合適的索引已經存在。

我假設(盡我所能從原始查詢中找出)是categories_views表僅包含用戶類別的「最新」視圖,即member_id, category_id是唯一的。如果原始查詢返回了正確的結果集(如果它自從用戶的該類別的「最後一個視圖」以來唯一返回的具有「新」元素的類別;否則,存在在categories_views表中的任何「老」 view_date值將觸發類的包容性,即使有,這是晚於在一個類別最新(最大added_date)元素的新view_date

如果是這種情況並非如此,即(member_id,category_id)不是唯一的,那麼查詢將需要改變。


查詢原questio n有點令人費解,它將element_views作爲表名或表別名,但不會出現在EXPLAIN輸出中。我打算假設element_views是爲了categories_views的同義詞。


對於原來的查詢,在elements表添加一個覆蓋索引:

... ON elements (category_id, added_date) 

的目標有得到解釋輸出顯示「使用索引」

您也可能嘗試添加索引:

... ON categories_views (member_id, category_id, added_date) 

要從categories_vie中獲取所有列w表(對於選擇列表),查詢將不得不訪問表中的頁面(除非有索引包含所有這些列。目標是通過使索引中的所有(或大部分)謂詞滿足來減少需要在數據頁上訪問以查找行的行數。


是否有必要從elements表返回category_id列?由於內連接謂詞,我們不知道這與categories_views表中的category_id列的值相同嗎?