升级到COMPATIBILITY_LEVEL 120时的慢SQL查询>>

问题描述 投票:0回答:1

我们已经在COMPATIBILITY_LEVEL <120中运行数据库已有一段时间了,因为我们无法查明为什么某些查询的运行速度非常慢。我不是觉得这是解决covid-19无聊问题的完美方法,因此我尝试解决新的CE(嗯...不再那么新)的问题。

因此,我得到了一个相当简单的查询,其中涉及3个表和2个表值参数

declare @spIDs as table (id int not null primary key);
INSERT INTO @spIDs values(1),(2); -- 169 in my sql script

DECLARE @subscriptionProductGroupMapping AS table
( 
    subscriptionProductID int not null,
    groupID int not null,
    primary key(subscriptionProductID, groupID)
);
INSERT INTO @subscriptionProductGroupMapping (subscriptionProductID, groupID) 
VALUES(101,101); -- 168 in my script

SELECT
    [dbo].[User].[userID]
FROM
    [dbo].[User]
    LEFT JOIN
    (
        SELECT DISTINCT [UserValidThrough].userID 
        FROM 
            [dbo].[UserValidThrough] 
            INNER JOIN @spIDs spIDs on(spIDs.id = [dbo].[UserValidThrough].subscriptionProductID)
    ) AS [uvt] ON [uvt].[userID] = [User].userID
    INNER JOIN 
    (
        SELECT DISTINCT userID
        FROM 
        GroupMembership
        INNER JOIN
        @subscriptionProductGroupMapping as SPIAndGroup ON(GroupMembership.groupID = SPIAndGroup.groupID)
    ) gms ON(gms.userID = [User].userID) 
WHERE
    [User].permissionType NOT IN(8, 16, 32, 64, 128) AND
    [User].deleteDate IS NULL AND
    [User].userTypeID IN(@userTypeID_0) AND
    [uvt].[userID] IS NULL 

当以兼容级别110运行此查询时,查询速度很快,少于0.3秒。当更改为兼容性级别120时,查询大约需要8-9秒才能执行! :(

[调查实际执行计划时,我发现有一个聚集索引查找分配了大约7秒的时间,因此我专注于该部分

Actual execution planExplanation of slow clustered Index seek

我已经尝试将此查询分解为另一个Table值参数,然后该查询又很快了。但是,这意味着我必须在许多地方重写我的应用程序,我真的很想知道为什么这样做很慢以及如何处理。

任何人都可以阐明这个问题吗?

编辑2020-04-15 12:57 CET这是一个调试脚本,它复制了一个简化的方案:1.创建调试表和调试数据

create table temp_User 
(
    userID int not null,
    -- Additional columns ommited for readability
    primary key (useriD)
);

create table temp_UserValidThrough 
(
    userID int not null,
    subscriptionProductID int not null,
    -- Additional columns ommited for readability
    primary key(userID, subscriptionProductID)
);

create table temp_GroupMembership
(
    userID int not null,
    groupID int not null,
    primary key(userID, groupID)
);


CREATE NONCLUSTERED INDEX temp_GroupMembership_GroupIDWithUserID 
ON [dbo].[temp_GroupMembership] ([groupID])
INCLUDE ([userID])

-- populate User
-- populate UserValidThrough
-- populate GroupMembership
declare @noUsers as int = 120000;
declare @noGroups as int = 400;

SET NOCOUNT ON;

declare @n as int = 0;
while @n < @noUsers
begin
    insert into temp_User values(@n);

    declare @rand as int = rand() * @noGroups;
    insert into temp_UserValidThrough VALUES(@n, @rand);
    insert into temp_GroupMembership VALUES(@n, @rand); 

    SET @n = @n + 1;
end;
  1. 此查询可以使用不同的COMPATIBILITY_LEVEL设置执行,并且性能会有很大差异。
DECLARE @userTypeID_0 AS Int;
SET @userTypeID_0 = '1';

declare @spIDs as table (id int not null primary key);
insert into @spIDs
select distinct groupID from temp_GroupMembership;

DECLARE @subscriptionProductGroupMapping AS table
( 
    subscriptionProductID int not null,
    groupID int not null,
    primary key(subscriptionProductID, groupID)
);
insert into @subscriptionProductGroupMapping
SELECT
    T.groupID as subscriptionProductID,
    T.groupID
FROM
    (select distinct groupID from temp_GroupMembership) AS T;


SELECT
    [User].[userID]
FROM
    [dbo].[temp_User] AS [User]
    --LEFT JOIN
    --(
    --  SELECT DISTINCT [UserValidThrough].userID 
    --  FROM 
    --      [dbo].[UserValidThrough] 
    --      INNER JOIN @spIDs spIDs on(spIDs.id = [dbo].[UserValidThrough].subscriptionProductID)
    --) AS [uvt] ON [uvt].[userID] = [User].userID
    INNER JOIN 
    (
        SELECT DISTINCT userID
        FROM 
        temp_GroupMembership as GroupMembership
        INNER JOIN
        @subscriptionProductGroupMapping as SPIAndGroup ON(GroupMembership.groupID = SPIAndGroup.groupID)
    ) gms ON(gms.userID = [User].userID) 
WHERE
    --[User].permissionType NOT IN(8, 16, 32, 64, 128) AND
    --[User].deleteDate IS NULL AND
    --[User].userTypeID IN(@userTypeID_0) AND
    NOT EXISTS 
    (
        SELECT DISTINCT [UserValidThrough].userID 
        FROM 
            [dbo].[UserValidThrough] 
            --INNER JOIN @spIDs spIDs on(spIDs.id = [dbo].[UserValidThrough].subscriptionProductID)
        WHERE
            [UserValidThrough].userID = [User].userID
            AND
            [UserValidThrough].subscriptionProductID IN(SELECT id from @spIDs)
    )
    --[uvt].[userID] IS NULL 

declare @lvl as varchar (10) = (SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME());

print 'COMPATIBILITY_LEVEL: ' + @lvl
-- COMPATIBILITY_LEVEL 110 time: average 242 ms
-- COMPATIBILITY_LEVEL 120 time: average 40 s! (200 times slower!)

我们已经在COMPATIBILITY_LEVEL <120中运行数据库已有一段时间了,因为我们无法查明为什么某些查询的运行速度非常慢。不,我觉得这是对covid-19的完美治疗方法...

sql-server query-performance compatibility-level
1个回答
0
投票

尝试一下:

© www.soinside.com 2019 - 2024. All rights reserved.