目的:
想要知道在尝试从已订购的CTE中检索有限数量的行时,哪种性能更快/更好。
示例:
假设我有一个CTE(故意简化),看起来像这样,我只想要前5行:
WITH cte
AS (
SELECT Id = RANK() OVER (ORDER BY t.ActionID asc)
, t.Name
FROM tblSample AS t -- tblSample is indexed on Id
)
哪个更快:
SELECT TOP 5 * FROM cte
OR
SELECT * FROM cte WHERE Id BETWEEN 1 AND 5 ?
备注:
答案 0 :(得分:1)
最重要的是要注意两个查询都不会始终生成相同的结果集。请考虑以下数据:
CREATE TABLE #tblSample (ActionId int not null, name varchar(10) not null);
INSERT #tblSample VALUES (1,'aaa'),(2,'bbb'),(3,'ccc');
这两个都会产生相同的结果:
WITH CTE AS
(
SELECT id = RANK() OVER (ORDER BY t.ActionID asc), t.name
FROM #tblSample t
)
SELECT TOP(2) * FROM CTE;
WITH CTE AS
(
SELECT id = RANK() OVER (ORDER BY t.ActionID asc), t.name
FROM #tblSample t
)
SELECT * FROM CTE WHERE id BETWEEN 1 AND 2;
现在让我们进行更新:
UPDATE #tblSample SET ActionId = 1;
在此更新之后,第一个查询仍返回两行,第二个查询返回3.请记住,在TOP查询中没有ORDER BY,结果无法保证,因为SQL中没有默认顺序。
有了这个 - 哪个表现更好?这取决于。它取决于您的索引,统计信息,行数以及SQL引擎的执行计划。
答案 1 :(得分:0)
前5个按照表中定义的索引选择任意5行,而1到5之间的Id尝试根据Id列获取数据,无论是索引搜索还是扫描取决于所选属性。两者都是两个不同的查询..如果您没有Id上的任何索引,则“查询之间的ID”可能会很慢,
让我试着用一个例子来解释......
请考虑这是您的数据..
create index nci_name on yourcte(id) include(name)
--drop index nci_name on yourcte
;with cte as (
select * from yourcte )
select top 5 * from cte
;with cte as (
select * from yourcte )
select * from cte where id between 1 and 5
首先我要创建包含名称的id的索引,现在如果你看到你的第二个查询做索引搜索,第一个进行索引扫描并选择前5,所以在这种情况下第二种方法更好
参见执行计划:
现在我正在删除索引 执行 - 在yourtable上的drop index nci_name
现在它对两种方法进行表扫描
如果您在两个表扫描中都注意到,在第一个扫描中它只读取5行,第二个方法读取10行并应用谓词
请参阅第一个计划的执行计划属性
对于第二种方法,它读取10行
现在第一种方法更好..
在你的情况下,这个索引需要在ActionId上,它决定了id。
因此,性能取决于您对基表的索引方式。
答案 2 :(得分:0)
为了获得您在cte中计算的RANK()
,必须按t.ActionID
对所有数据进行排序。排序是一种阻塞操作:必须在输出单行之前处理整个输入。
因此,在这种情况下,您是否选择任意五行,或者如果您选择排在堆顶部的五行可能无关紧要。