我正在尝试找出表中是否存在某行。使用MySQL,以下哪种查询方式更好:
SELECT COUNT(*) AS total FROM table1 WHERE ...
检查总数是否为非零,还是最好像这样查询:
SELECT * FROM table1 WHERE ... LIMIT 1
并且检查是否返回了任何行?
在两个查询中,WHERE子句使用了索引。
我正在尝试找出表中是否存在某行。使用MySQL,以下哪种查询方式更好:
SELECT COUNT(*) AS total FROM table1 WHERE ...
检查总数是否为非零,还是最好像这样查询:
SELECT * FROM table1 WHERE ... LIMIT 1
并且检查是否返回了任何行?
在两个查询中,WHERE子句使用了索引。
你也可以尝试使用EXISTS
:
SELECT EXISTS(SELECT * FROM table1 WHERE ...)
根据文档所述,您可以在 EXISTS 子查询中使用任何 SELECT 语句。
传统上,EXISTS 子查询以 SELECT * 开始,但它也可以以 SELECT 5 或 SELECT column1 或任何内容开头。 MySQL 忽略此类子查询中的 SELECT 列表,因此不会产生任何影响。
最近我对这个主题进行了一些研究。如果字段是 TEXT 字段,非唯一字段,则实现方式必须不同。
我对 TEXT 字段进行了一些测试。考虑到我们有一个包含 1M 条记录的表。其中有 37 个条目等于 'something':
SELECT * FROM test WHERE text LIKE '%something%' LIMIT 1
with
mysql_num_rows()
:0.039061069488525s。(更快)SELECT count(*) as count FROM test WHERE text LIKE '%something%
:
16.028197050095s。SELECT EXISTS(SELECT 1 FROM test WHERE text LIKE '%something%')
:
0.87045907974243s。SELECT EXISTS(SELECT 1 FROM test WHERE text LIKE '%something%' LIMIT 1)
:
0.044898986816406s。但是,用 BIGINT PK 字段时,只有一项等于 '321321':
SELECT * FROM test2 WHERE id ='321321' LIMIT 1
with
mysql_num_rows()
:0.0089840888977051s。SELECT count(*) as count FROM test2 WHERE id ='321321'
:
0.00033879280090332s。SELECT EXISTS(SELECT 1 FROM test2 WHERE id ='321321')
:
0.00023889541625977s。SELECT EXISTS(SELECT 1 FROM test2 WHERE id ='321321' LIMIT 1)
:
0.00020313262939453s。(更快)SELECT 1 FROM test WHERE texte LIKE '%something%' LIMIT 1
查询会更好。 - Laurent W.select 1 ... limit 1
,那么用exists包围是没有意义的。 - Adrien HorgniesEXISTS (SELECT ...)
和EXISTS (SELECT ... LIMIT 1)
没有区别。MySQL足够聪明,会自动插入LIMIT 1
,因为这就是EXISTS
的工作原理:当找到至少一个结果时,它就停止。 - Ruslan Stelmachenkomysql> SELECT * FROM table_1;
+----+--------+
| id | col1 |
+----+--------+
| 1 | foo |
| 2 | bar |
| 3 | foobar |
+----+--------+
3 rows in set (0.00 sec)
mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 1);
+--------------------------------------------+
| EXISTS(SELECT 1 FROM table_1 WHERE id = 1) |
+--------------------------------------------+
| 1 |
+--------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 9);
+--------------------------------------------+
| EXISTS(SELECT 1 FROM table_1 WHERE id = 9) |
+--------------------------------------------+
| 0 |
+--------------------------------------------+
1 row in set (0.00 sec)
使用别名:
mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 1) AS mycheck;
+---------+
| mycheck |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
在我的研究中,我发现以下速度的结果。
select * from table where condition=value
(1 total, Query took 0.0052 sec)
select exists(select * from table where condition=value)
(1 total, Query took 0.0008 sec)
select count(*) from table where condition=value limit 1)
(1 total, Query took 0.0007 sec)
select exists(select * from table where condition=value limit 1)
(1 total, Query took 0.0006 sec)
我觉得值得指出的是,在评论中曾经提到过,就是在这种情况下:
SELECT 1 FROM my_table WHERE *indexed_condition* LIMIT 1
优于:
SELECT * FROM my_table WHERE *indexed_condition* LIMIT 1
这是因为第一个查询可以通过索引满足,而第二个查询需要进行行查找(除非可能使用的索引中包含了表的所有列)。
添加LIMIT
子句可以让引擎在找到任何一行后停止。
第一个查询应该与以下查询类似:
SELECT EXISTS(SELECT * FROM my_table WHERE *indexed_condition*)
虽然在这里(1/*)没有区别,但它向引擎发送相同的信号,但我仍然会写1来加强使用EXISTS
时的习惯:
SELECT EXISTS(SELECT 1 FROM my_table WHERE *indexed_condition*)
如果您需要在没有匹配行时显式返回,则添加EXISTS
包装可能是有意义的。
建议您不要使用Count
,因为每次使用count都会为数据库增加额外负载。相反,可以使用SELECT 1
,如果查询到记录就返回1,否则返回null,从而达到更好的效果。
有时候,如果存在行的自增主键(id
),则获取它非常方便;如果不存在,则返回0
。
以下是如何在单个查询中完成此操作:
SELECT IFNULL(`id`, COUNT(*)) FROM WHERE ...
IFNULL(id, 0)
而不是COUNT(*)
? - Ethan Hohensee使用COUNT查询更快,虽然可能不太明显,但就获取所需结果而言,两种方法都足够。
COUNT(1)
。它比COUNT(*)
更快,因为COUNT(*)
会测试该行中至少一个列是否!= NULL。你不需要这个,特别是因为你已经有了一个条件(WHERE
子句)。相反,COUNT(1)
测试的是1
的有效性,它始终是有效的,并且测试时间要少得多。
...EXISTS( SELECT 1/0 FROM someothertable)
。对于 SQL Server 和 Oracle,使用 *、1 或 NULL 没有区别,因为 EXISTS 只是基于 WHERE 条件匹配的布尔值测试。 - OMG PoniesSELECT 1 FROM table1 WHERE col = $var LIMIT 1
比你的查询更快。那么你的查询有什么优势呢? - Shafizadeh