2011-08-19 209 views
3

我有这个users表:MySQL查询优化需要

id : int (255) 
name: char (100) 
last_comment_target: int(100) 
last_comment_date: datetime 

此表有大约1.3mil行。

PKEYBTREEidlast_comment_targetlast_comment_date

而且,我想执行一系列查询:

SELECT * FROM users 
WHERE id IN (1,2,3,5,...[around 5000 ids]) 
AND last_comment_target > 0 
ORDER BY last_comment_dt DESC LIMIT 0,20; 

有时查询可以采取只要3秒钟。我想知道是否有更好的方法来优化这个查询。或者,如果这个查询可以被重写。

非常感谢您的帮助。

+0

你从哪里得到5000个ID? – Jacob

+0

5000个ID来自哪里?如果你可以把它们放到一个表格中(或者它们已经在表格中)并且进行连接,它可能会更快。更好的是,如果5000个ID可以与用户中的属性相关联,那么您可以将其指定为简单条件 - 如果需要,甚至可以对其进行索引。 –

+0

这5000个ID是手动插入还是可以查询? – AJC

回答

1
SELECT u.* 
FROM 
    users u 
    JOIN (
     SELECT 1 id 
     UNION ALL 
     SELECT 2 id 
     UNION ALL 
     : 
     : 
     SELECT 5000 id 
    ) ids ON ids.id = u.id 
WHERE 
    last_comment_target > 0 
ORDER BY 
    last_comment_dt DESC 
LIMIT 0, 20; 
+0

谢谢。我想知道你能否帮助我解释一下你的答案。为什么我们使用'SELECT 1 id UNION ALL SELECT 2 id UNION ALL ....'作为'JOIN'的一部分?我们真的可以在我们从另一个表派生的表上做一个'JOIN'吗?它会有什么不同(如果有的话)? –

+0

@Heru这将创建一个所有ID的临时表。连接表通常是一个更快的解决方案,但它取决于很多因素,你应该测试它。如果你有一些其他表中的所有ID,那么你可以使用你的其他表,而不是这些UNION:'select id from other_table' – Karolis

+0

谢谢@Karolis - 我相信内部连接更好。 –

0

谢谢大家的贡献。

@Karolis似乎替代使用join代替range

所以,基本上指出:

SELECT * FROM users WHERE id IN (1,2,3,...[5000 ids]) AND last_comment_target > 0

单产EXPLAIN声明RANGEtype。 5000个ID可以从另一个表中生成。

当我切换上面:

SELECT * 
FROM users u 
INNER JOIN user_friends uf ON u.id = uf.to_id 
AND u.last_comment_target > 0 
AND uf.from_id = [id]; 

它产生于EXPLAIN语句包含两个typesrefeq_ref这是快于range在此查询。

查询执行从3+秒减少到0.2x秒左右。

所以,教训从我结束了解到:TRY使用JOIN而不是RANGE如果你有,你可以从派生表。