【问题标题】:SQL Server select query taking long time to execute with WHERE clauseSQL Server 选择查询需要很长时间才能使用 WHERE 子句执行
【发布时间】:2019-01-08 13:40:34
【问题描述】:

我有一个表 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

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

【问题讨论】:

  • 为什么需要这张支票?我不明白这一点:如果你已经知道你不会找到任何结果,为什么要运行查询?无论如何,您可以改用coalesce,这会有所帮助。但也许我误解了你的编辑。请解释并发布完整的声明(可以像以前一样跳过确切的列)

标签: sql-server-2012


【解决方案1】:

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

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

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

【讨论】:

  • 感谢您的回复。我有 10 到 15 列。所以我包括添加所有这些列?
  • 如果我包含所有这些列,那么它会影响插入、删除、更新操作的任何性能问题吗?
  • 我刚刚启动了我的 Studio,并尝试了我的旧代码,该代码已发布,并且运行良好。以毫秒为单位给出结果。我不知道是什么问题。
  • 如果索引包含 ALL 您的查询需要的列,则该索引仅是 覆盖 - 所以是的,如果您的查询需要 15 列,您必须将它们全部包含在覆盖索引中。是的,当然,任何索引都将花费一点点额外时间来维护 - 这是SELECT 的更快查询性能与其他操作的更多开销之间的权衡 - 只有你可以决定是否值得
猜你喜欢
  • 2018-07-06
  • 1970-01-01
  • 1970-01-01
  • 2016-04-22
  • 2021-12-25
  • 2016-06-17
  • 1970-01-01
  • 2017-12-08
相关资源
最近更新 更多