[英]TSQL query that uses function and view is very slow
Ok, first of all thanks in advance if you read through this whole thing as it may be quite painful on several levels. 好的,首先要提前感谢你,如果你仔细阅读了这一切,因为它可能会在几个层面上非常痛苦。
But on the plus side, after reading through this whole thing I have a feeling the answer is very obvious and simple, so you have that going for you. 但从好的方面来说,在阅读完整篇文章之后,我感觉答案是非常明显和简单的,所以你有这个适合你。
So I'll tell you the problem in a nutshell, and then in more detail: 所以我会简单地告诉你这个问题,然后更详细地说:
Nutshell 果壳
Grandpappy.Grandpa.Dad.Me
. Grandpappy.Grandpa.Dad.Me
。 Detailed description 详细说明
Here are the tables that indicate children and parents. 以下是表明儿童和父母的表格。 In this example we will be dealing with Fruits, Vegetables, and Planets.
在这个例子中,我们将处理水果,蔬菜和行星。
Let's take a look at them... 我们来看看他们......
Table 1 = Planets
(I have no parents) 表1 =
Planets
(我没有父母)
ID, Name
1, Earth
2, Saturn
Table 2 = Fruits
(my parent is either a planet or a fruit) 表2 =
Fruits
(我的父母要么是行星要么是水果)
ID, Name, PlanetName, FruitName
1, Kiwi, Earth, null
2, Strawberry, Saturn, null
3, Banana, null, Strawberry
Table 3 = Vegetables
(my parent is planet or a fruit or a vegetable) 表3 =
Vegetables
(我的父母是行星或水果或蔬菜)
ID, Name, FruitName, PlanetName, VegetableName
1, Potato, Kiwi, null, null
2, Squash, null, Earth, null
3, Pumpkin, null, null, Potato
Table 4 = BigTable
(this will be the one the main slow query is using. It has a column that contains just a child's name and it could be a planet or a fruit or a vegetable) 表4 =
BigTable
(这将是主要的慢查询使用的那个。它有一个只包含一个孩子名字的列,它可能是一个行星或水果或蔬菜)
ID, Name, OneOfTheThree
1, John, Earth
2, Steve, Kiwi
3, Joe, Saturn
4, Jane, Potato
We have our tables and we have our data, what do I want to do now? 我们有表格,我们有数据,现在我想做什么?
I want to create a query that looks at all of the OneOfTheThree values in the BigTable and find out what their lineage is (who there dads, grand parents etc are) and return that to the caller. 我想创建一个查询,查看BigTable中的所有OneOfTheThree值,并找出他们的血统(爸爸,祖父等等)是什么,并将其返回给调用者。
So my thought was to do this: 所以我的想法是这样做:
So I did it as follows: 所以我这样做了:
My view 我的观点
View = vwEverybodyAndTheirParents
View =
vwEverybodyAndTheirParents
-- Planets
SELECT Name, null AS Parent
FROM Planets
UNION
-- Fruits
SELECT Name, PlanetName AS Parent
FROM Fruits
UNION
-- Vegetables
SELECT Name, CASE WHEN FruitName IS NOT NULL THEN FruitName WHEN PlanetName IS NOT NULL THEN Planet ELSE NULL END AS Parent
FROM Vegetables
Ok, that gives me everything and it's parents. 好吧,这给了我一切,它是父母。 Now for the function to crawl that view and give me the period delimited string of the full ancestry:
现在,对于抓取该视图的函数,并为我提供完整祖先的句点分隔字符串:
My function 我的功能
CREATE FUNCTION dbo.fnGetMyParent(@NameToGetParentsFor varchar(255))
RETURNS varchar(255)
AS
DECLARE @InternalName varchar(255)
DECLARE @ParentName varchar(255)
DECLARE @ConcatenatedParentStringToReturn varchar(max)
SELECT @ParentName = Parent
,@ConcatenatedParentStringToReturn = Name
FROM vwEverybody
WHERE Name = @NameToGetParentsFor
WHILE @ParentName IS NOT NULL
BEGIN
SELECT @InternalName = Name,
@ParentName = Parent
FROM vwEverybody
WHERE Name = @ParentName
SET @ConcatenatedParentStringToReturn = RTRIM(InternalName) + "." + RTRIM(@ConcatenatedParentStringToReturn)
END
RETURN @ConcatenatedParentStringToReturn
END
This function works fine (though could be poorly coded and poorly performing?), so with all the above examples if I were to call it like so: 这个函数工作正常(虽然可能编码不好,性能不佳?),所以上面的所有例子如果我这样调用它:
dbo.fnGetMyParent('Potato')
I get back the concatenated string of: 我找回了串联的字符串:
Earth.Kiwi.Potato
The problem 问题
Ok, so now to finally get to the problem... the big query that takes forever: 好的,所以现在最终解决问题......永远需要的大问题:
SELECT Name,
OneOfTheThree,
fnGetMyParent(OneOfTheThree) as HeirarchyOfParents
FROM BigTable
I can see why it could take so long as for each value it executes the function which needs to then crawl a view. 我可以看到为什么它可能需要花费很长时间才能执行需要随后抓取视图的函数的每个值。 So...
所以...
My questions to you 我向你提问
A BIG THANK YOU if you made it this far! 非常感谢你,如果你做到这一点!
First of all when using sql you should avoid using loops as much as you can (unless the situation asks for it) 首先,当你使用sql时,你应该尽量避免使用循环(除非情况要求)
Second, there is no need of the view, or of the function as your query should be easily written in one go. 其次,不需要视图或函数,因为您的查询应该很容易一次写入。
select
bt.Name
,bt.OneOfTheThree
,p.Name+'.'+isnull(f.Name,'')+'.'+isnull(v.Name,'')+'.'+bt.Name as HeirarchyOfParents
from BigTable bt
left join Vegetables v
on bt.OneOfTheThree = v.name
left join Fruits f
on coalesce(v.FruitName,bt.OneOfTheThree) = f.Name
left join Planets p
on coalesce(f.PlanetName,v.PlanetName,bt.OneOfTheThree) = p.Name
The last join you can remove if the table is consistent with the others, as it does not bring new information (the planet name is already there). 如果表与其他表一致,则可以删除最后一个连接,因为它不会带来新信息(行星名称已经存在)。
The improvements that you can bring here are with indexes on the tables, if you are able to do that. 如果你能够做到这一点,你可以带来的改进是表上的索引。
Ok, with the new information, the easiest way I can think of is the following: 好的,有了这些新信息,我能想到的最简单的方法如下:
;with ftemp as (
select
name as path
,PlanetName
,name as root
,name as name
,FruitName as parent
,0 as cnt
from fruits
union all
select
fruits.name + '.' + ftemp.path
,ftemp.PlanetName
,root
,fruits.name
,cnt+1
from fruits
join ftemp
on fruits.name= ftemp.parent
)
,fg as (
select
name
,max(cnt) as cnt
from ftemp
group by name
)
,f as (
select
ftemp.*
from ftemp
join fg
on ftemp.cnt = fg.cnt
and ftemp.name = fg.name
)
,vtemp (same ideea)
,vg (same ideea)
,v (same ideea)
select
bt.Name
,bt.OneOfTheThree
,p.Name+'.'+isnull(f.Path+'.','')+isnull(v.Path+'.','')+bt.Name as HeirarchyOfParents
from BigTable bt
left join v
on bt.OneOfTheThree = v.name
left join f
on coalesce(v.FruitName,bt.OneOfTheThree) = f.Name
left join Planets p
on coalesce(f.PlanetName,v.PlanetName,bt.OneOfTheThree) = p.Name
With this approach though .. I have no idea on the performance it will yield. 但是通过这种方法......我不知道它会产生什么样的性能。 So it's up to you to complete the query and test.
因此,您需要完成查询和测试。
Hope it helps. 希望能帮助到你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.