2010-11-02 57 views
0

我有一個類似於Q & stackoverflow的功能的系統。主要的區別是帽子每個問題具有過期日期時間:MySQL:在ORDER BY查詢中加入並使用索引

CREATE TABLE questions (
    id INT NOT NULL AUTO_INCREMENT, 
    title CHAR(100) NOT NULL, 
    details TEXT 
    PRIMARY KEY (id) 
) 

CREATE TABLE answers (
    id INT NOT NULL AUTO_INCREMENT, 
    question_id INT NOT NULL 
    details TEXT 
    expiration_datetime DATETIME 
    score INT 
    PRIMARY KEY (id) 
) 

欲與由得分排序的前N個未過期的答案一起顯示的問題。我想是這樣的:

SELECT * FROM questions, answers 
WHERE questions.id=1 AND questions.id=answers.question_id AND answers.expiration_datetime > NOW() 
ORDER BY answers.score DESC LIMIT 10 

幾個問題:

1)是最有效的方式做到我想要的東西上面的查詢?它與明確使用JOIN有什麼不同,如:

SELECT * FROM questions JOIN answers ON questions.id=answers.question_id 
WHERE questions.id=1 AND answers.expiration_datetime > NOW() 
ORDER BY answers.score DESC LIMIT 10 

2)如何使我的查詢使用索引?我正在考慮在TABLE答案中加入這個索引:

INDEX (question_id, expiration_datetime, score) 

上述索引適用於我的查詢嗎?這看起來不正確,因爲expiration_datetime升序,而我需要得分降序。我能在這裏做什麼?

回答

0

用INNER JOIN或FROM子句連接表給出了相同的執行計劃。然而,前者更容易閱讀(這是1992年以來的標準)。

只要有可能,您的RDBMS將使用索引。打印執行計劃通常是一個好主意(EXPLAIN SELECT * FROM -- ...)。但是請注意,創建多列索引可能會非常棘手。在你的情況下,你可以使用question_id上的索引,但是在expiration_datetime或分數上使用而不是,因爲它們不是索引的第一列。你將不得不做三個不同的索引。

P.S. SELECT *不被推薦。始終輸入您需要的列(易於閱讀和重新閱讀),並只提及您將使用的列。無需選擇,例如,如果您從未在腳本中使用此列,initial_date!

+0

您確定expiration_datetime不會被使用嗎? MySQL可以使用多列索引,並且(question_id,expiration_datetime)形成索引的最左側部分。所以我不明白爲什麼它不會被使用。 – Continuation 2010-11-02 18:06:57