让我们使用以下脚本创建一个简单的表order(id: int, category: int, order_date: int)
IF OBJECT_ID('dbo.orders', 'U') IS NOT NULL DROP TABLE dbo.orders
SELECT TOP 1000000
NEWID() id,
ABS(CHECKSUM(NEWID())) % 100 category,
ABS(CHECKSUM(NEWID())) % 10000 order_date
INTO orders
FROM sys.sysobjects
CROSS JOIN sys.all_columns
现在,我有两个等效的查询(至少我相信它们是等价的):
-- Q1
select distinct o1.category,
(select count(*) from orders o2 where order_date = 1 and o1.category = o2.category)
from orders o1
-- Q2
select o1.category,
(select count(*) from orders o2 where order_date = 1 and o1.category = o2.category)
from (select distinct category from orders) o1
然而,当我运行这些查询时,它们具有明显不同的特征。对于我的数据,Q2快两倍,这显然是由于查询计划在加入之前首先找到唯一类别(以下查询计划中的哈希匹配)这一事实。
如果添加请求索引
,差异仍然存在CREATE NONCLUSTERED INDEX ix_order_date ON orders(order_date)
INCLUDE (category)
此外,Q2也可以有效地使用以下指数,而Q1保持不变:
CREATE NONCLUSTERED INDEX ix_orders_kat ON orders(category, order_date)
我的问题是:
修改
我对这个问题的动机是,我想理解为什么查询优化器在重写甚至简单查询方面都很差,而且它们依赖于SQL语法。 SQL语言是一种声明性语言,因此,为什么SQL查询处理器经常被语法驱动,即使是像这样的简单查询呢?
答案 0 :(得分:0)
查询功能等效,这意味着它们应返回相同的数据。
但是,SQL引擎会对它们进行不同的解释。第一个(SELECT DISTINCT
)生成所有结果,然后删除重复项。
第二个首先提取不同的值,因此子查询仅在适当的子集上调用。
索引可能会使查询更有效,但它不会从根本上影响distinct
处理是在子查询之前还是之后发生。
在这种情况下,结果是相同的。但是,根据子查询,这不一定是真的。