sql - 按 : 分区的 Row_Number() 性能优化

标签 sql sql-server stored-procedures query-optimization row-number

我一直在尝试优化在表 (Table1) 和子查询之间保留连接的存储过程的性能。当部门表中的记录增加时,速度会变慢;我认为,这是由于 ROW_NUMBER 函数造成的。它适用于部门表中记录数量较少的情况。 Table1 和存储过程末尾的子查询之间有一个左联接。

下面是示例表Table1EmployeeDepartment,涉及运行缓慢的查询。

CREATE TABLE [Table1]
(
    [ID] [int] NOT NULL PRIMARY KEY, 
    [Name] VARCHAR(250) NOT NULL,
    [DepartmentID] int 
) ON [PRIMARY] 

INSERT [Table1] ([ID], [Name], [DepartmentID])  
VALUES (1, N'A', 1), (2, N'D', 2),  
       (3, N'C', 3), (4, N'E', 4),
       (5, N'D', 5), (6, N'A', 6),
       (7, N'B', 7)  
GO 

CREATE TABLE [Department]
(
    [DepartmentID] [int] NOT NULL PRIMARY KEY, 
    [Name] VARCHAR(250) NOT NULL, 
) ON [PRIMARY] 

INSERT [Department] ([DepartmentID], [Name])  
VALUES (1, N'Engineering'), (2, N'Administration'),  
       (3, N'Sales'), (4, N'Marketing'), 
       (5, N'Finance') 
GO 

CREATE TABLE [Employee]
( 
    [EmployeeID] [int] NOT NULL PRIMARY KEY, 
    [FirstName] VARCHAR(250) NOT NULL, 
    [LastName] VARCHAR(250) NOT NULL, 
    [DepartmentID] [int] NOT NULL 
         REFERENCES [Department](DepartmentID), 
) ON [PRIMARY] 
GO

INSERT [Employee] ([EmployeeID], [FirstName], [LastName], [DepartmentID]) 
VALUES (1, N'Orlando', N'Gee', 1), (2, N'Keith', N'Harris', 2), 
       (3, N'Donna', N'Carreras', 3), (4, N'Janet', N'Gates', 3) 

运行缓慢的示例查询。

SELECT 
    *
FROM
    Table1 AS t
LEFT JOIN 
    (SELECT 
         D.Name,
         E.DepartmentID,
         ROW_NUMBER() OVER (PARTITION BY E.DepartmentID
                            ORDER BY D.DepartmentID ASC,
                                     CASE WHEN D.Name IS NULL THEN 1 ELSE 0 END ASC, D.Name ASC) AS ord_index
     FROM 
         Department AS D
     INNER JOIN 
         Employee AS E ON D.DepartmentID = E.DepartmentID) AS x ON x.DepartmentID = t.DepartmentID
WHERE 
    x.ord_index = 1 OR x.ord_index IS NULL

我尝试根据调优顾问的建议添加索引,但它并没有提高性能。我也尝试使用 APPLY,但由于 ROW_NUMBER 函数而无法弄清楚。不过,我一直在尝试浏览该平台上的相关标题。

我很感谢任何优化此类查询的指南。

最佳答案

您可以重构查询以使用外部应用,这可能会产生更好的执行计划(取决于支持的索引),例如:

select * from Table1 t 
outer apply (
    select D.Name,
        Row_Number() over (partition by E.DepartmentID order by D.DepartmentID asc, 
        case when D.Name is null then 1 
        else 0 end asc, D.Name asc) as ord_index 
    from Department D 
    join Employee E on D.DepartmentID = E.DepartmentID
    where E.DepartmentID = t.DepartmentID 
) x 
where x.ord_index = 1 or x.ord_index is null

参见DB<>Fiddle showing better plan

关于sql - 按 : 分区的 Row_Number() 性能优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71228659/

相关文章:

sql-server - TSQL在存储过程中动态添加列

sql - 如何递增 id 字段的所有存储值

sql - 给定一个用户 ID,获取他们所有的收件人 channel 和最后一条消息预览?

sql - 在 SQL 中重命名表时在表名中使用变量

sql-server - 在不使用 order by 子句的情况下生成 DENSE_RANK() - SQL Server

java - 在java中执行存储过程后出现ClassCastException

postgresql - PostgreSQL 可以在过程中声明过程吗?

mysql - 创建DATABASE时的SQL_MODE和TIME_ZONE

sql - 将全名拆分为名字和姓氏

SQL Server 查询连接优化