2012-04-15 106 views
1

我有50万行,看起来像这样的表:http://d.pr/njFJ提高MySQL查询的任何提示?

enter image description here

这样的查询有时往往需要超过2秒:

SELECT * 
FROM `alerts` 
WHERE `a_timestamp` > '2012-04-15' AND `a_timestamp` <= '2012-04-16' 
    AND a_company_id IN(64,65,69,70,71,72,73,74,75,76,83,86,106,108,109,116,148) ORDER BY a_id DESC 

这里的解释查询:http://d.pr/z20b

enter image description here

有人可以指出我做错了什么吗?也许我错过了一些东西。它应该在这样一张小桌子上花费那么多时间吗?

+0

图片坏对不起 – Joel 2012-04-15 18:20:52

+0

@ Joel :)他们在哪里?图像清晰。 – Lion 2012-04-15 18:24:15

+1

您是否尝试颠倒索引中的列顺序? IE浏览器。 a_company_id,a_timestamp? – 2012-04-15 18:28:23

回答

1

试图消除IN子句。它会对整个表格扫描 IN clause中的每个值,导致性能下降。

您可以使用临时表,用于存储ID和使用带有ID在临时表,而不是使用in条款JOIN,

+0

嗯。这是所有INs的问题还是仅仅在我的特定情况下?在这种情况下,我可以删除company_id条件并使用PHP进行过滤 - 实际上并不是太多。另外有意思的是,EXPLAIN查询只显示1087行... – Salmon 2012-04-15 18:41:05

+0

我不认为'IN'子句会强制任何表扫描... – 2012-05-22 15:25:59

2

由于翠鸟提到摆脱IN条款(通常是在查询性能瓶颈)和用JOIN代替它,但不使用临时表,你这是怎么做到这一点:

SELECT alerts.* FROM (
    (SELECT 64 AS id) UNION (SELECT 65) UNION (SELECT 69) UNION (SELECT 70) 
    UNION (SELECT 71) UNION (SELECT 72) UNION (SELECT 73) UNION ... 
) AS ids 
INNER JOIN alerts ON (ids.id = alerts.a_company_id) 
WHERE alerts.a_timestamp > '2012-04-15' AND alerts.a_timestamp <= '2012-04-16' 
ORDER BY ids.id DESC 

,并确保你在a_company_id有一个索引。

+0

谢谢,会试试看。时间戳上的单独索引和单独的a_company_id? – Salmon 2012-04-15 18:54:38

+0

对于这个查询,只有'a_company_id'上的索引将很重要我不认为MySql在'a_timestamp'这里使用你的索引。 – nobody 2012-04-15 18:57:19

1

尝试在(a_company_id,a_timestamp)...上创建索引... type_ts_company索引的相反顺序。

+0

最终的问题是时间戳记上的范围查询无法使用索引,因为范围查询不能很好地进行优化。反转索引允许company_id IN限制范围查询必须查看的值 - 因为它只需检查公司ID列表中的值,而不是检查表中的所有值。 – 2012-06-03 08:26:35

+0

范围查询肯定可以使用索引。如果范围列不是索引关键字中的最后一个,则效率不高。如果此数据库中有成千上万个company_id,则首先在索引中使用range列,那么mysql将不得不通过数千个不匹配的company_id进行筛选。但是,如果company_id是第一个,它可以通过对每个单独的company_id进行范围搜索。这样做十几个比过滤出数以千计的不匹配的记录要好。 – bobwienholt 2012-06-04 14:00:39