2012-01-24 69 views
0

我有兩個表,一個存儲用戶會話,另一個存儲購物車數據。 sessions有一個cart_id列,該列與carts表中的相應id匹配。我正試圖在基於數據庫的會話上運行垃圾回收。首先,我刪除過期會話:Sloooow垃圾收集查詢

DELETE FROM sessions WHERE expires < NOW(); 

然後,我刪除了現在孤立的,換句話說車,沒有會話,其cart_id匹配這一個。

DELETE `carts` 
FROM `carts` 
LEFT OUTER JOIN `sessions` 
ON `carts`.`id` = `sessions`.`cart_id` 
WHERE `sessions`.`cart_id` IS NULL 

這最後一個查詢真的很慢,就像超過60秒種慢。

我已經試過這一個,而不是:

DELETE `cart` 
FROM `cart` 
WHERE `cart`.`id` NOT IN (SELECT `cart_id` FROM `sessions`) 

這也是緩慢的。任何指針?

+0

你對'sessions.cart_id'的指數? –

+0

我沒有索引。這可能是我的問題,呃? *吝嗇退縮閱讀索引手冊* – Rob

+0

你肯定需要索引列(你經常)用於連接。 –

回答

1

確保您的sessions.expires和sessions.cart_id列已建立索引。

如果您的網站流量很高,並且正在添加大量購物車/會話,那麼由於併發性,您的刪除操作將會變慢。

你貼將永遠是,如果你有很多會議的很慢的最後操作使用IN語句時(在密切將需要一對一的比較,每個ID)。

經驗法則: IN值計數應該相對較小。

+0

他的查詢很好。你爲什麼不這樣想? –

+0

MySQL刪除查詢規範('DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name' ...)沒有在FROM語句之前列出表名。 –

+0

哦,我的糟糕的ypercube,只是看到我沒有指定我在回答中提到哪個查詢。 –

2

你可以把它轉過來。讓每個購物車參考會話ID通過FOREIGN KEY和設置ON DELETE CASCADE。這樣,當您刪除會話中的一行時,與其關聯的購物車也會被刪除。

CREATE TABLE session (session_id INT NOT NULL, 
         expires DATE NOT NULL, 
        PRIMARY KEY (session_id), 
        INDEX expires_index (expires) 
) ENGINE=INNODB;       

CREATE TABLE cart (id INT, 
        session_id INT, 
        INDEX session_index (session_id), 
        FOREIGN KEY (session_id) REFERENCES session(session_id) ON DELETE CASCADE 
) ENGINE=INNODB; 

如果你發現,它需要太多的時間來刪除所有過期限制做小刪除更頻繁。

DELETE FROM session WHERE expires < NOW() ORDER BY expires LIMIT 10;