【发布时间】:2014-06-02 17:57:56
【问题描述】:
好的,首先感谢您通读整篇文章,因为它在多个层面上可能会非常痛苦。
- 这篇文章很长
- 太恶心了
- 这可能会让你的大脑受伤
但从好的方面来说,通读整篇文章后,我觉得答案非常明显和简单,所以你可以做到。
所以我会简单地告诉你这个问题,然后更详细地告诉你:
简而言之
- 我在 SQL Server 2008r2 中有一个查询需要很长时间才能完成。
- 我有几个表,其中包含有关孩子及其父母的信息。
- 一个表中的子级可以在另一个表中有父级,然后在另一个表中可以有父级(只有 3 个表)。
- 我希望能够将孩子的名字作为字符串,并找出其祖先的层次结构并将其作为句点分隔的字符串返回。所以
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 值并找出他们的血统(父亲、祖父母等是谁)并将其返回给调用者。
所以我的想法是这样做:
- 创建一个视图,将三个表(Planet、Fruit、Vegetable)拉到一个显示 Name 和 Parent 的视图中。
- 创建一个接受名称的函数。然后它使用该视图来找出该名称的父级。然后它会查看该 Parent 的 Parent 是谁,并且一直持续到 Parent 为 null 并且它停止(因为这是祖先链的顶部......我们一直到没有父母的 Planet )。
- 创建一个查询来查询 BigTable,然后在 BigTable 的 OneOfTheThree 列上使用上述函数来获取 OneOfTheThree 中名称的祖先。
所以我是这样做的:
我的看法
查看 = 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 sql-server performance tsql sql-server-2008-r2