【问题标题】:Improve SQL CTE query performance提高 SQL CTE 查询性能
【发布时间】:2011-12-19 11:24:05
【问题描述】:

有什么方法可以提高下面CTE查询的性能(@E@R是实际系统中带索引的表):

DECLARE @id bigint = 1

DECLARE @E TABLE
(
id bigint,
name varchar(50)
)

DECLARE @R TABLE
(
child_id bigint,
parent_id bigint
)

INSERT INTO @E SELECT 1, 'one'
INSERT INTO @E SELECT 2, 'two'
INSERT INTO @E SELECT 3, 'three'
INSERT INTO @E SELECT 4, 'four'
INSERT INTO @E SELECT 5, 'five'
INSERT INTO @E SELECT 6, 'six'
INSERT INTO @E SELECT 7, 'seven'

INSERT INTO @R SELECT 1, 2
INSERT INTO @R SELECT 1, 3
INSERT INTO @R SELECT 3, 4
INSERT INTO @R SELECT 5, 4
INSERT INTO @R SELECT 3, 6
INSERT INTO @R SELECT 7, 4

; WITH cte
(
child_id,
parent_id
)

AS (

SELECT * FROM @R R
WHERE R.child_id = @id

UNION ALL
SELECT R.* FROM @R R
INNER JOIN cte ON CTE.parent_id = R.child_id

)
SELECT * FROM @E E
WHERE e.id = @id
UNION ALL
SELECT P.* FROM @E E
INNER JOIN cte ON 1=1
INNER JOIN @E P ON P.id = cte.parent_id
WHERE e.id = @id
ORDER BY 1

预期结果:

id | name
1  | one 
2  | two
3  | three
4  | four
6  | six

在现实世界的数据中,我将处理@R 中的数百万行和@E 中的大约十万行。所以我想看看是否有什么我可以做的来挤出更多的性能。

编辑:到目前为止,只是为了澄清和总结,R 上有一个带有 child_id, parent_id 的聚集 pk 索引,向 @r.parent_id 添加索引也将提高连接性能。

有什么可以改进的吗?在使用inner join 1=1 进行 CTE 之后的一点是,这里有什么可以改进的地方吗?我可以做任何其他架构设计来获得具有更好性能的类似父子映射吗?

【问题讨论】:

  • 确保任何用于连接的列都已编入索引,例如child_idparent_id 等等 - 这将提高 JOIN 性能
  • 你知道在你的真实数据中你可能有多少级别的亲子关系吗?
  • @marc_s 此表的 [child_id, parent_id] 上会有一个聚集索引。
  • @MarkBannister:现实世界的数据可能只下降到 10 级左右,最多 20 级,但没有直接限制。
  • @Seph:这还不够好 - 您应该在 (child_id)(parent_id) 上都有单独的索引以加快 JOIN 性能。如果您在 (child_id, parent_id) 上有一个复合索引,那么它可以单独用于 child_id - 但不能单独用于 parent_id(它需要两者)

标签: sql sql-server performance common-table-expression


【解决方案1】:

正如 marc_s 指出的那样

此表在 [child_id, parent_id] 上的聚集索引还不够好 - 您应该在 (child_id)(parent_id) 上都有单独的索引以加快 JOIN 性能。如果您在 (child_id, parent_id) 上按此顺序有一个复合索引,那么它可以单独用于 child_id - 但不能单独用于 parent_id(它需要两者) – marc_s 2011-12-19 12:35 /p>

这极大地提高了查询的性能并帮助我了解 CTE 查询在内部是如何工作的。

【讨论】:

    【解决方案2】:

    一开始:

    DECLARE @E TABLE
    (
        id BIGINT PRIMARY KEY,
        name varchar(50)
    )
    
    DECLARE @R TABLE
    (
        child_id bigint,
        parent_id BIGINT,
        PRIMARY KEY(child_id, parent_id),
        UNIQUE (parent_id, child_id)
    )
    

    但是,请记住,Sql Server 在优化 CTE 方面非常差。

    【讨论】:

    • 你有SQL Server is very poor in optimizing CTEs的证据吗?这不是我个人的经历......
    • 所以,我会客气一点 - 有时 SQL Server 在优化 CTE 方面很差。 8-) 如果您想要适当的证据 - 我会尝试弄清楚,但我已经多次遇到这种行为。
    • 记住问题 - 如果你使用排名函数 - ROW_NUMBER(),例如,在 CTE 内部 - CTE 变得非常缓慢
    • @Oleg:你确定这不是因为你使用了 ROW_NUMBER() 按非索引列排序,不是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-26
    • 2016-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多