首页 > 解决方案 > SQL Server 选择查询需要很长时间才能使用 WHERE 子句执行

问题描述

我有一张表Table1,其中包含 1 - 150 万行带有主键的行。

这是我的表结构

CREATE TABLE [dbo].[Table1]
(
    [Id] [INT] NOT NULL,    
    [allow_public] [BIT] NULL,
    [average_frequency] [DECIMAL](18, 4) NULL,
    [category_id] [INT] NULL,
    -- a few more columns
    --
    --
    --
    [member_id] [INT] NULL

    CONSTRAINT [PK_Table1_Id] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
)

像这样添加了一个非聚集索引member_id

CREATE NONCLUSTERED INDEX non_cluster_index_member_table1
    ON dbo.Table1 (member_id) 
    WHERE member_id IS NOT NULL;
    GO

当我执行查询时

SELECT
    [id], 
    [accurate_grams],
    [allow_public],
    [average_frequency],
    [category_id]
FROM
    dbo.Table1 
WHERE 
    member_id = @memberid;

它在几毫秒内返回一些行。但是当我执行类似的查询时

SET @OrgMemberId = ISNULL(@OrgMemberId, -1);

SELECT
    [id], 
    [accurate_grams],
    [allow_public],
    [average_frequency],
    [category_id]
FROM 
    dbo.Table1 f
WHERE 
    ISNULL(f.member_id, -1) = CASE 
                                 WHEN @MemberId = -1 
                                    THEN ISNULL(f.member_id, -1) 
                                    ELSE @MemberId 
                              END

完成执行需要很多时间。

注意member_id列包含空值。并且它没有被映射为外键

    ISNULL(f.member_id, -1) = CASE 
                                 WHEN @MemberId = -1 
                                    THEN ISNULL(f.member_id, -1) 
                                    ELSE @MemberId 
                              END

写上一行的原因是 - 有时用户将空值发送到@MemberId. 为了处理这种情况,我在 where 子句中使用了这一行。在单个查询中,我可以获取两个不同的结果。member_id is null然后查询时选择所有记录,然后查询时仅member_id is not null选择与Member_id. 所以没有必要使用if else.

有没有其他解决方案来处理这个问题?

标签: sql-server-2012

解决方案


一种可能的方法是使用覆盖索引 - 一个包含查询需要返回的所有列的索引:

CREATE NONCLUSTERED INDEX ncix_table1_member_id
ON dbo.Table1 (member_id) 
INCLUDE (id, accurate_grams, allow_public, average_frequency, category_id)
WHERE member_id IS NOT NULL;
GO

使用这种方法,现在只需查看索引就可以“满足”您的查询 - 它不必对实际表的数据页进行大量(相当昂贵的)“键查找”来获取“缺失”查询的列值


推荐阅读