一直很疑惑exist的用法,他在比较
比如说两张表一张是用户表TDefUser(userid,address,phone),一张是消费表TAccConsume(userid,time,amount),我要查消费超过5000的用户记录,那么我可以写
select * from TDefUser
where exists (select 1 from TAccConsume where TDefUser.userid=TAccConsume.userid and TAccConsume.amount>5000)
也可以写
select * from TDefUser
where userid in (select userid from TAccConsume where TAccConsume.amount>5000)据说是exists的效率比较好,可是我不太知道exists的执行过程是怎么样的,它会把两张表join么?
它的True和False是怎么返回的,怎么知道exists判断的是那列,我没有指定列阿?
select 1 代表什么意思呢?这个问题困挠我好久了,请帮帮忙
比如说两张表一张是用户表TDefUser(userid,address,phone),一张是消费表TAccConsume(userid,time,amount),我要查消费超过5000的用户记录,那么我可以写
select * from TDefUser
where exists (select 1 from TAccConsume where TDefUser.userid=TAccConsume.userid and TAccConsume.amount>5000)
也可以写
select * from TDefUser
where userid in (select userid from TAccConsume where TAccConsume.amount>5000)据说是exists的效率比较好,可是我不太知道exists的执行过程是怎么样的,它会把两张表join么?
它的True和False是怎么返回的,怎么知道exists判断的是那列,我没有指定列阿?
select 1 代表什么意思呢?这个问题困挠我好久了,请帮帮忙
==============
师傅说因为exists只返回真或假,select 1 可以提高效率。
那是否意味着我把1改成任何一个其他的值效率都一样呢
比如说select * from TDefUser
where exists (select 5 from TAccConsume where TDefUser.userid=TAccConsume.userid and TAccConsume.amount>5000)
可能原因是1是效率,2是MS可能在未来的版本不支持in了.3是现在的in 是MS向老版本mssql兼容用的,4.....
这是数据有记录的话 我还要把所以的记录都返回回来!他们这这样的一个比较 不是1和5 的比较!
其运行方式是先运行主查询一次 再去子查询里查询与其对应的结果 如果是ture则输出,反之则不输出.再根据主查询中的每一行去子查询里去查询.in()后面的子查询 是返回结果集的,换句话说执行次序和exists()不一样.子查询先产生结果集,然后主查询再去结果集里去找符合要求的字段列表去.符合要求的输出,反之则不输出.
其运行方式是先运行主查询一次 再去子查询里查询与其对应的结果 如果是ture则输出,反之则不输出.再根据主查询中的每一行去子查询里去查询.in()后面的子查询 是返回结果集的,换句话说执行次序和exists()不一样.子查询先产生结果集,然后主查询再去结果集里去找符合要求的字段列表去.符合要求的输出,反之则不输出.
------------------------------------------
执行顺序如下:
1.首先执行一次外部查询
2.对于外部查询中的每一行分别执行一次子查询,而且每次执行子查询时都会引用外部查询中当前行的值。
3.使用子查询的结果来确定外部查询的结果集。
如果外部查询返回100行,SQL 就将执行101次查询,一次执行外部查询,然后为外部查询返回的每一行执行一次子查询。但实际上,SQL的查询
优化器有可能会找到一种更好的方法来执行相关子查询,而不需要实际执行101次查询。
select a.code,a.name from table a
where a.code in(select b.code from table b where a.name like 'A')select b.code from table b where a.name like 'A'这名返回的是一个结果集,在执行上面的语句时,首先从TABLE表中取一条记录,再看这条记录的CODE记录是否在子查询返回的结果集中。如当前取得是‘001’,子查询返回的结果集是
001
002
003
则条件条件。而exists()返回是一个逻辑值,如果子查询有结果值则返回TRUE,否则返回FALSE
主查询检查返回的结果值决定是否要当前的记录行。一般EXISTS的执行效率高一些。
数据(注意因为有聚集索引,实际存储也是按以下次序的)
1 2006-1-1 200
1 2006-1-2 300
1 2006-1-2 500
1 2006-1-3 2000
1 2006-1-3 2000
1 2006-1-4 400
1 2006-1-5 500
2 2006-1-1 200
2 2006-1-2 300
2 2006-1-2 500
2 2006-1-3 2000
2 2006-1-3 6000
2 2006-1-4 400
2 2006-1-5 8000
3 2006-1-1 7000
3 2006-1-2 30000
3 2006-1-2 50000
3 2006-1-3 20000语句:
select * from TDefUser
where exists (select 1 from TAccConsume where TDefUser.userid=TAccConsume.userid and TAccConsume.amount>5000)对于userid=1,需要找所有记录,才返回false,与第三个语句的效率差不多
对于userid=2,找到2006-1-3的记录,就返回true,比第三个语句的效率高
对于userid=3,第一条记录就返回true,比第三个语句的效率高语句
select * from TDefUser
where userid in (select userid from TAccConsume where TAccConsume.amount>5000)返回空记录集
2
2
3
3
3
3再判断语句
select * from TDefUser
where userid in (select userid from TAccConsume where userid=TDefUser.userid and amount>5000)对于userid=1,需要找所有记录,返回空记录集,比较判断
对于userid=2,需要找所有记录,返回记录集
2
2
,比较判断
对于userid=3需要找所有记录,返回记录集
3
3
3
3
,比较判断
用IN(耗时0.01秒):SELECT *
FROM dbo.判定结果
WHERE ((工程编号 + 项目编号) IN
(SELECT b.工程编号 + b.项目编号
FROM 判定结果 AS b
GROUP BY b.工程编号, b.项目编号
HAVING SUM(b.检测项数) > 0))用EXSIS(耗时23秒):SELECT *
FROM dbo.判定结果 a
WHERE EXISTS
(SELECT 1
FROM dbo.判定结果 AS b WHERE a.工程编号 + a.项目编号 = b.工程编号 + b.项目编号
GROUP BY b.工程编号, b.项目编号
HAVING SUM(b.检测项数) > 0
)
a、是因为要用in,只能选择一个结果,被迫把两个字段连接在一起的,那就可以改成如下:
SELECT *
FROM dbo.判定结果 a
WHERE EXISTS
(SELECT 1
FROM dbo.判定结果 AS b WHERE a.工程编号 = b.工程编号
and a.项目编号= b.项目编号
GROUP BY b.工程编号, b.项目编号
HAVING SUM(b.检测项数) > 0
)
如果(工程编号,项目编号)有索引,那这个语句会用到索引,数据量大的时候exists的效率会大很多,如果检测项数都是非负数,还可以改为:
SELECT *
FROM dbo.判定结果 a
WHERE EXISTS
(SELECT 1
FROM dbo.判定结果 AS b WHERE a.工程编号 = b.工程编号
and a.项目编号= b.项目编号
and b.检测项数 > 0
)
效果更明显b、很特殊的,比如(工程编号=01,项目编号=1011)和(工程编号=011,项目编号=011)当作相同的,也就是说必须用 (工程编号 + 项目编号)来判断,那肯定用不到索引了
至于1秒和23秒,我想一方面数据不多,本来效率差别不大,另一方面,会不会和测试有关,同一语句多执行几次,以不要计算第一次的平均为准来测试才公平。
Exists 时,不需要比对,
所以 Exists比in效率要高.
exists在查询的时候只要有一个记录符合条件,那么它就返回true,这样查询次数少,信息返回量也少。而in是返回所有符合条件的记录集。所以一般exists比in好。
但是 b615n(周围走) 又举了个例子,我相信他测试的结果是正确的,造成这种结果的原因也很正常,在数据量不是太大的情况下,in很好的利用了索引所有查询效率高。这点很重要,合理利用索引对擦选效率有很大的提高。