查询
SELECT row
FROM `table`
USE INDEX(`indexName`)
WHERE row1 = '0'
AND row2 = '0'
AND row3 >= row4
AND (row5 = '0' OR row5 LIKE 'value')
我有以下MySQL查询,我已经创建了一个使用索引;
CREATE INDEX indexName ON `table` (row1, row2, row3, row5);
然而,表现并不是很好。它在5到12秒的任何地方从一个5.9百万行表中提取大约17,000多行。
似乎瓶颈是row3
> = row4
- 因为代码中没有该部分,它在0.6-0.7秒内运行。
(来自评论)
行(占位符列名)实际上是表中的id(主键,索引)列,这是我稍后输出的结果集。我正在输出与我的查询中的参数匹配的ID数组,然后从该数组中选择一个随机ID,以通过特定行上的最终查询收集数据。这是作为rand()的变通方法完成的。根据这些知识需要进行任何调整吗?
答案 0 :(得分:0)
17K行不是一个微小的结果集。大型结果集通常需要时间,因为将数据从MySQL服务器传递到请求它们的程序的开销。
您在'value'
中使用的row5 LIKE 'value'
的内容对于查询效果非常重要。如果'value'
以%
之类的通配符开头,则查询速度会很慢。
话虽如此,你需要一个所谓的covering index。您已尝试使用您创建的索引创建一个。它很接近但并不完美。
您的查询过滤了row1
,row2
和row5
上与常量值的相等性,因此这些列应该位于索引的第一位。查询计划程序可以随机访问您的索引到第一个匹配的条目,然后顺序扫描索引,直到它到达最后一个匹配的条目。这个速度和它一样快。
然后,您要检查row3
和row4
(以比较它们)。这些列应该在索引中接下来。最后,如果您的查询的SELECT
子句提到了table
中的列的子集,则应将其余列放在索引中。因此,根据您问题中的查询,您的索引应为
CREATE INDEX indexName ON `table` (row1, row2, row5, row3, row4, row);
查询规划器将能够通过使用所谓的索引范围扫描扫描索引的子集来满足整个查询。那要快得多。
专业提示:请勿强制查询计划员使用USE INDEX()
。相反,构建索引以有效地处理您的查询。
答案 1 :(得分:0)
索引不能用于比较同一个表中的两列(充其量,它可以用于索引扫描而不是表扫描,如果所有输出字段都包含在索引中),那么基本上没有"正确"这样做的方法。
如果你可以控制结构和填充表的过程,你可以添加一个计算字段来保存两个字段之间的差异。然后将该字段添加到索引并调整查询以使用该字段而不是其他字段。
它很漂亮,并没有提供很大的灵活性(例如,如果你想比较另一个领域,你需要添加它等),但它确实完成了工作。
答案 2 :(得分:0)
(这是http://mysql.rjweb.org/doc.php/random)
的改编让我们实际将随机化折叠到查询中。这将消除收集一堆ID,处理它们,然后再回到表中。它还可以避免需要额外的索引。
id
值。id
像...一样的东西。
SELECT b.* -- should replace with actual list of columns
FROM
( SELECT id
FROM tbl
WHERE id >= ( SELECT MIN(id) +
( MAX(id) - MIN(id)
- 22 -- somewhat avoids running off end
) * RAND()
FROM tbl )
AND col1 = 0 ... -- your various criteria
ORDER BY id
LIMIT 1
) AS a
JOIN tbl AS b USING(id);
优点/缺点:
RAND()
点击的时间太晚,则不会返回任何内容。在这种(罕见)情况下,再次运行查询,但从0开始。id
中的巨大差距将导致id
返回的偏差。 (上面的链接讨论了一些处理这种问题的方法。)