我有点感觉为什么视图较慢:where子句可能不会同时应用。但结果看起来似乎是一样的。我不知道我能做些什么,没有使用视图...这是不理想的,因为我添加了视图以避免代码重复,我不想删除它,如果没有必要。
有关更改我这样做的方法的任何建议,以便我可以使用命令1中的视图,但仍然可以在命令2中执行我的查询时快速执行吗?
declare @foo varchar(50)
set @foo = 'be%'
ALTER VIEW [dbo].[wpvw_v]
AS
select distinct [name]
from kvgs kvg left join cdes cde
on kvg.kvgi = cde.kgi
group by [name], cde.kgi, kvg.mU
having count(cde.kgi) >= 2 or kvg.mU = 1 or
exists (select [name] from FP x where x.name = kvg.name)
--Command 1: Takes 7 seconds
select [name] from wpvw_v where name like @foo
--Command 2: Takes 1 second
SELECT DISTINCT kvg.name
FROM dbo.kvgs AS kvg LEFT JOIN
dbo.cdes AS cde ON kvg.kvgi = cde.kgi
where name like @foo
GROUP BY kvg.name, cde.kgi, kvg.mU
HAVING (COUNT(cde.kgi) >= 2) OR
(kvg.mU = 1) OR
EXISTS
(SELECT Name
FROM dbo.FP AS x
WHERE (Name = kvg.name))
答案 0 :(得分:1)
您在查看中的查询是这样的:
SELECT name FROM (SELECT DISTINCT name FROM ...) WHERE name = @name;
而第二个是:
SELECT DISTINCT name FROM ... WHERE name = @name;
这两个查询是非常不同的,即使它们产生相同的结果,只有扫描整个表以产生不同的名称才可以回答furst,而第二个只能扫描你感兴趣的名称in。
问题的要点是DISTINCT
的存在会产生一个障碍,它不允许过滤谓词沿着查询树向下移动到有效的地方。
<强>更新强>
即使DISTINCT不是障碍,第二眼看第二眼也有更强大的障碍:GROUP BY / HAVING子句。一个查询在应用GROUP和HAVING条件后过滤,另一个在之前。 HAVING条件具有再次引用name
的子查询。我怀疑QO可以在聚合之前证明过滤的等价性并在聚合之后过滤。
答案 1 :(得分:1)
我认为HAVING子句不能容纳您发布的内容,但我相信您应该编写您的视图以使用UNION。这是我的看法:
ALTER VIEW [dbo].[wpvw_v] AS
WITH names AS(
SELECT k.name
FROM KVGS k
WHERE EXISTS(SELECT NULL
FROM CDES c
WHERE c.kgi = k.kvgi
GROUP BY c.kgi
HAVING COUNT(c.kgi) > 1)
UNION ALL
SELECT k.name
FROM KVGS k
WHERE k.mu = 1
GROUP BY k.name
UNION ALL
SELECT k.name
FROM KVGS k
JOIN FP x ON x.name = k.name
GROUP BY k.name)
SELECT n.name
FROM names n
如果要过滤掉3个SQL语句之间的重复项,请将UNION ALL
更改为UNION
。然后你可以使用:
SELECT n.name
FROM wpvw_v n
WHERE CHARINDEX(@name, n.name) > 0
答案 2 :(得分:0)
据我所知,视图的完整结果集被收集,然后被使用它的SELECT语句进一步淹没。这与您的第二个SELECT语句非常不同,后者不会收集任何超出需要的语句。
答案 3 :(得分:0)
您可以尝试使用内联表函数(http://www.sqlhacks.com/index.php/Retrieve/Parameterized-View),但是我认为这有点像黑客。
老实说,我可能会去重复代码。我没有像看到其他代码一样看到SQL - 我一直看到其他逻辑上等价的语句之间的性能存在巨大差异。
答案 4 :(得分:0)
如果没有看到更多(例如,每个表的CREATE TABLE,INDEX和CONSTRAINT语句),并且最好将查询计划视为代表连接基数的一些示例数据,那么很难说。
可能在查询之间存在语义差异,这与查询LIKE表达式的排序规则有关,并且可能无法同步计划。
但是,这里可能有足够的空间进行查询调优。您似乎不太可能需要完全聚合所有COUNT()。您有三个相当不同的条件,您希望在结果中看到“名称”。使用UNION,您可以使其中一个或多个更容易计算,如果并发不是问题,您甚至可以将其写为多步骤用户定义的表值函数,该函数在单独的步骤中累积名称
答案 5 :(得分:0)
我相信以下内容可以重现您的问题:
create table tbl (idx int identity(1,1), name varchar(50), val float)
declare @cnt int
set @cnt=0
while @cnt < 10000
begin
insert tbl select char(CAST(rand()*256 AS INT)), rand()
set @cnt = @cnt + 1
end
go
create view tbl_view as select distinct name from tbl group by name having sum(val) > 1
然后,如果您运行以下查询:
SET STATISTICS IO ON
declare @n varchar(50)
set @n='w%'
select * from tbl_view where name like @n
SET STATISTICS IO OFF
GO
SET STATISTICS IO ON
declare @n varchar(50)
set @n='w%'
select distinct name from tbl where name like @n group by name having sum(val) > 1
SET STATISTICS IO OFF
您将获得以下内容:
(1 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tbl'. Scan count 1, logical reads 338, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
Table 'tbl'. Scan count 1, logical reads 338, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
视图强制它首先处理子表,然后才应用过滤器。现在,如果您修改视图并删除 DISTINCT ,则不会更改。但是,如果您修改视图以通过以下方式删除组:
create view tbl_view as select name from tbl where val > 0.8 group by name
go
SET STATISTICS IO ON
declare @n varchar(50)
set @n='w%'
select * from tbl_view where name like @n
SET STATISTICS IO OFF
GO
SET STATISTICS IO ON
declare @n varchar(50)
set @n='w%'
select name from tbl where val > 0.8 and name like @n group by name
SET STATISTICS IO OFF
然后,您会得到两个查询相同的结果:
(1 row(s) affected)
Table 'tbl'. Scan count 1, logical reads 34, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
Table 'tbl'. Scan count 1, logical reads 34, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
所以看起来 HAVING 似乎是障碍。
答案 6 :(得分:0)
表值函数往往比视图更快,假设您的WHERE条件已知且可以在参数中提供。
表值函数的一个优点是可以有多个语句,因此可以在后续语句中将OUTER JOIN转换为更快的INNER JOINS。所以不要这样:
INSERT INTO @resultTable
table1_id,
table1_column,
table2_column,
table3_column
SELECT
table1.id,
table1.column,
table2.column,
table3.column
FROM
table1
INNER JOIN table2 ON table2.table1_id = table1.id
LEFT OUTER JOIN table3 ON table3.table1_id = table1.id
return @resultTable
...你可以做到这一点,我发现它总是更快:
INSERT INTO @resultTable
table1_id,
table1_column,
table2_column,
SELECT
table1.id,
table1.column,
table2.column,
FROM
table1
INNER JOIN table2 ON table2.table1_id = table1.id
UPDATE @resultTable SET
table3_column = table3.column
FROM @resultTable AS result
INNER JOIN table3 ON table3.table1_id = result.table1_id
return @resultTable