我试图找出表中是否存在一行。使用MySQL,最好执行以下查询:

SELECT COUNT(*) AS total FROM table1 WHERE ...


并检查总数是否为非零,还是执行以下查询更好?

SELECT * FROM table1 WHERE ... LIMIT 1


,并检查是否返回了任何行?

在两个查询中,WHERE子句都使用索引。 />

#1 楼

您还可以尝试EXISTS

SELECT EXISTS(SELECT * FROM table1 WHERE ...)


,根据文档,您可以SELECT进行任何操作。


传统上,EXISTS子查询以SELECT *开头,但可以
以SELECT 5或SELECT column1或其他任何内容开头。 MySQL
会忽略此类子查询中的SELECT列表,因此没有区别。


评论


用... EXISTS(从其他表中选择1/0)进行测试。对于SQL Server和Oracle,使用*,1或NULL没什么区别,因为EXISTS仅基于1+的WHERE条件匹配来测试布尔值。

–OMG小马
09年11月4日在23:28

伙计们,它在该答案第二段链接的文档中说:“传统上,EXISTS子查询以SELECT *开头,但它可以以SELECT 5或SELECT column1或其他任何形式开头。MySQL会忽略此类中的SELECT列表。子查询,因此没有区别。”

– mpen
2012年2月11日下午0:39

@ChrisThompson:执行该语句后会发生什么?我的意思是结果集包含什么?

–阿什温
2012年11月4日,11:37

@Ashwin,它包含0(不存在)还是1(存在)。

– fedorqui'停止伤害'
13年2月7日在9:09

我认为您的查询是多余的,经过测试,此查询SELECT 1 FROM table1 WHERE col = $ var LIMIT 1比您的查询更快。那么查询的优势是什么?

– Shafizadeh
2015年9月28日15:20在

#2 楼

我最近对此问题做了一些研究。如果该字段是TEXT字段(非唯一字段),则实现方式必须有所不同。
我已经对TEXT字段进行了一些测试。考虑到我们有一个包含1M条目的表这一事实。 37个条目等于'something':


SELECT * FROM test WHERE text LIKE '%something%' LIMIT 1
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
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。 (更快)



评论


感谢您的其他答复。您是否发现TEXT字段的两个最快选项之间的时间差异相当一致?差异似乎并不大,在两种情况下使用SELECT EXISTS(SELECT 1 ... LIMIT 1)似乎都不错。

–Bernard Chen
2012年5月22日7:15

没错,就文本字段的其他结果而言,差异并不重要。不过,使用SELECT 1 FROM test WHERE texte LIKE'%something%'LIMIT 1也许查询会更好

– Laurent W.
2012年6月4日20:08



我在mysql上尝试过,在使用select 1 ... limit 1的情况下,将select包围起来是没有用的

– Adrien Horgnies
16年5月15日在9:57

@LittleNooby有区别。 SELECT EXISTS ...给出true和false值(1或0),而SELECT 1 ...给出1或为空。虚假值和空集之间有细微的差别,具体取决于您的情况。

–快速选择
16年5月17日在23:30

@LittleNooby提出了一个很好的观点,这很容易忽略。上面的时序测试中缺少SELECT 1 FROM test WHERE ...,但周围没有SELECT EXISTS。大概是这样的头发更快。

–ToolmakerSteve
16年9月2日在15:06

#3 楼

@ChrisThompson答案的简短示例

示例:

mysql> 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)


#4 楼

在我的研究中,我发现结果以跟随的速度前进。

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) 


评论


Laravel(php框架)正在使用最后一个。

–MartiaHiblite
10月28日3:04

#5 楼

我认为值得指出的是,尽管在评论中已提及到这种情况:

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 / *在这里没有区别),但在使用EXISTS时,我仍然会写1来加强习惯:

SELECT EXISTS(SELECT 1 FROM my_table WHERE *indexed_condition*)


如果在没有行匹配的情况下需要显式返回,则添加EXISTS包装可能是有意义的。

#6 楼

建议您不要使用Count,因为count总是会使数据库使用SELECT 1来增加数据库的负担,如果您的记录在那里,则返回1,否则返回null即可处理。

#7 楼

COUNT查询虽然不是很明显,但速度更快,但就获得所需结果而言,两者都足够了。

评论


但是,这是特定于数据库的。已知COUNT(*)在PostgreSQL中很慢。最好选择PK列,看看它是否返回任何行。

– BalusC
09年11月4日在21:05

尽管COUNT(*)在InnoDB中很慢

–将
2012年6月21日在20:16

#8 楼

有时,获取行的自动增量主键(id)(如果存在)和0(如果不存在)非常方便。这是在单个查询中可以做到的方式: br />
SELECT IFNULL(`id`, COUNT(*)) FROM WHERE ...


评论


为什么不只在这里使用IFNULL(id,0)而不是COUNT(*)?

– Ethan Hohensee
17年8月28日在18:35

#9 楼

对于非InnoDB表,您还可以使用信息模式表:

http://dev.mysql.com/doc/refman/5.1/en/tables-table.html

#10 楼

我会选择COUNT(1)。它比COUNT(*)更快,因为COUNT(*)进行测试以查看该行中是否至少有一列为!= NULL。您不需要它,尤其是因为您已经有一个条件(WHERE子句)。相反,COUNT(1)会测试1的有效性,该有效性始终有效并且需要更少的时间进行测试。

评论


-1这是错误的。 COUNT(*)不查看列值-只是计算行数。在这里查看我的答案:stackoverflow.com/questions/2876909/…

–马克·拜尔斯
2010年5月28日在21:35

COUNT()比EXISTS慢得多,因为EXISTS第一次找到行时可以返回

–将
2012年6月21日20:17

#11 楼

或者您可以将原始sql部分插入条件中
,这样我就有
'conditions'=> array('Member.id NOT IN((SELECT Membership.member_id FROM成员身份AS Membership)')

#12 楼

COUNT(*)在MySQL中进行了优化,因此一般而言,前一个查询可能会更快。

评论


您是指MyISAM在选择整个表的计数方面的优化吗?如果出现WHERE条件,我认为这没有帮助。

–Bernard Chen
09年11月4日在21:14