[英]TSQL query that uses function and view is very slow
好的,首先要提前感謝你,如果你仔細閱讀了這一切,因為它可能會在幾個層面上非常痛苦。
但從好的方面來說,在閱讀完整篇文章之后,我感覺答案是非常明顯和簡單的,所以你有這個適合你。
所以我會簡單地告訴你這個問題,然后更詳細地說:
果殼
Grandpappy.Grandpa.Dad.Me
。 詳細說明
以下是表明兒童和父母的表格。 在這個例子中,我們將處理水果,蔬菜和行星。
我們來看看他們......
表1 = Planets
(我沒有父母)
ID, Name
1, Earth
2, Saturn
表2 = Fruits
(我的父母要么是行星要么是水果)
ID, Name, PlanetName, FruitName
1, Kiwi, Earth, null
2, Strawberry, Saturn, null
3, Banana, null, Strawberry
表3 = Vegetables
(我的父母是行星或水果或蔬菜)
ID, Name, FruitName, PlanetName, VegetableName
1, Potato, Kiwi, null, null
2, Squash, null, Earth, null
3, Pumpkin, null, null, Potato
表4 = BigTable
(這將是主要的慢查詢使用的那個。它有一個只包含一個孩子名字的列,它可能是一個行星或水果或蔬菜)
ID, Name, OneOfTheThree
1, John, Earth
2, Steve, Kiwi
3, Joe, Saturn
4, Jane, Potato
我們有表格,我們有數據,現在我想做什么?
我想創建一個查詢,查看BigTable中的所有OneOfTheThree值,並找出他們的血統(爸爸,祖父等等)是什么,並將其返回給調用者。
所以我的想法是這樣做:
所以我這樣做了:
我的觀點
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
好吧,這給了我一切,它是父母。 現在,對於抓取該視圖的函數,並為我提供完整祖先的句點分隔字符串:
我的功能
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
這個函數工作正常(雖然可能編碼不好,性能不佳?),所以上面的所有例子如果我這樣調用它:
dbo.fnGetMyParent('Potato')
我找回了串聯的字符串:
Earth.Kiwi.Potato
問題
好的,所以現在最終解決問題......永遠需要的大問題:
SELECT Name,
OneOfTheThree,
fnGetMyParent(OneOfTheThree) as HeirarchyOfParents
FROM BigTable
我可以看到為什么它可能需要花費很長時間才能執行需要隨后抓取視圖的函數的每個值。 所以...
我向你提問
非常感謝你,如果你做到這一點!
首先,當你使用sql時,你應該盡量避免使用循環(除非情況要求)
其次,不需要視圖或函數,因為您的查詢應該很容易一次寫入。
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
如果表與其他表一致,則可以刪除最后一個連接,因為它不會帶來新信息(行星名稱已經存在)。
如果你能夠做到這一點,你可以帶來的改進是表上的索引。
好的,有了這些新信息,我能想到的最簡單的方法如下:
;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
但是通過這種方法......我不知道它會產生什么樣的性能。 因此,您需要完成查詢和測試。
希望能幫助到你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.