MySQL 有效测试 count w/ where 是不是大于一个值
Posted
技术标签:
【中文标题】MySQL 有效测试 count w/ where 是不是大于一个值【英文标题】:MySQL efficient test if count w/ where is greater than a valueMySQL 有效测试 count w/ where 是否大于一个值 【发布时间】:2017-04-04 22:54:58 【问题描述】:有没有办法优化下面的查询?
SELECT count(*)>1000 FROM table_with_lot_of_rows WHERE condition_on_index;
使用这个查询,mysql 首先执行count(*)
,然后进行比较。当只有少数行满足条件时,这很快,但如果很多行满足条件,则可能需要很长时间。有没有办法在找到 1000 个项目后立即停止计数,而不是遍历所有结果?
特别是,我对具有全文条件的 MyISAM 表感兴趣,但对 InnoDB 和/或基本 WHERE 子句的任何回答都会有所帮助。
【问题讨论】:
【参考方案1】:SELECT 1
FROM table_with_lot_of_rows
WHERE condition_on_index
LIMIT 1000, 1;
这样工作:
-
使用索引(估计比使用数据快)
跳过 1000 多行,收集任何内容。 (这比其他答案更好。)
如果到此为止,请获取 1 行,其中仅包含文字
1
(在 SELECT
中)。
现在您要么有一个空结果集(1(至少 1001 行)。
然后,根据您的应用程序语言,很容易区分这两种情况。
另一个注意事项:如果这是一个更大查询中的子查询,那么做
EXISTS ( SELECT 1
FROM table_with_lot_of_rows
WHERE condition_on_index
LIMIT 1000, 1 )
返回 TRUE/FALSE(与 1 或 0 同义)。
面对现实,扫描 1001 行,甚至是索引,都需要 一些 时间。我认为我的配方是最快的。
要检查的其他事项:这是 InnoDB 吗? EXPLAIN
是否说“使用索引”?多少内存? innodb_buffer_pool_size
的设置是什么?
请注意,InnoDB 现在有 FULLTEXT,因此没有理由坚持使用 MyISAM。
如果您使用的是 MyISAM 并且 WHERE
是 MATCH...
,那么我所说的大部分内容可能不适用。 FULLTEXT
可能在让引擎的其余部分有机会使用 ORDER BY
和 LIMIT
进行这些游戏之前获取所有结果。
请向我们展示实际查询,即EXPLAIN
和SHOW CREATE TABLE
。真正的目标是什么?看看一个查询是否会提供“太多”的结果?
可能的改进(取决于上下文)
由于我的初始SELECT
返回标量1
或NULL
,它可以用于任何布尔上下文,例如WHERE
。 1
是TRUE
,NULL
将被视为FALSE
。因此EXISTS
可能是多余的。
另外,1
/NULL
可以这样转换成1
/0
。注意:额外的括号是必需的。
IFNULL( ( SELECT ... LIMIT 1000,1 ), 0)
【讨论】:
很好的解决方案,谢谢!提供我的具体设置的详细信息可能与这个问题无关,这是为了改进基本的count(*)>1000
,与索引无关。
FULLTEXT
、SPATIAL
、PRIMARY
和其他索引有 4 种不同的工作方式。
在我提供赏金之后,我想出了一个修改版本,得到我想要的“0
or 1
”而不是“nothing or 1
”作为结果,没有重复阈值(违反 DRY),但它仍然是基于子查询的(感觉很难看)。我会留下赏金,看看是否有人可以在没有样式点子查询的情况下做到这一点,但除此之外,赏金是你激励我的。我的修改版本只是将它包装到COUNT
你的查询结果:SELECT COUNT(*) FROM (SELECT 1 FROM table_with_lot_of_rows WHERE condition_on_index LIMIT 1000, 1);
【参考方案2】:
您可以使用带有 LIMIT 的子查询来优化查询:
SELECT count(*)>1000 FROM (
SELECT 0 table_with_lot_of_rows
WHERE condition_on_index
LIMIT 1001
) as truncated_count;
在这种情况下,只要有足够的行满足条件,MySQL 就会停止。
【讨论】:
以上是关于MySQL 有效测试 count w/ where 是不是大于一个值的主要内容,如果未能解决你的问题,请参考以下文章
MySQL - 在 WHERE 子句中使用 COUNT(*)