【问题标题】:Why is this query taking so long to execute in SQL Server?为什么这个查询在 SQL Server 中执行需要这么长时间?
【发布时间】:2017-01-21 08:52:58
【问题描述】:

我想减少执行时间。这是我的查询:

SELECT 
    StoreID,
    ItemLookupCode,
    sum(TotalQuantity) TotalQuantity,
    sum(ExtendedPrice) ExtendedPrice,
    sum(ExtendedCost) ExtendedCost
FROM 
    [HQMatajer].[dbo].[JCF_ItemDailySalesParent]
WHERE
    time >= CONVERT(DATETIME, '2015-01-01 00:00:00', 102) AND
    time <= CONVERT(DATETIME, '2015-12-31 00:00:00', 102)
GROUP BY 
    ItemLookupCode, StoreID

执行此查询需要 3 分 33 秒。该表中的记录总数为 800 万。从数据库中检索到的总行记录数为 87,000

我为所有列创建了索引。

表定义

[StoreID]             [nchar](150)      NOT NULL,
[ItemLookupCode]      [nvarchar](25)    NULL,
[ExtendedDescription] [varchar](3000)   NULL,
[DepartmentID]        [int]             NULL,
[DepartmentName]      [nvarchar](30)    NULL,
[CategoryID]          [int]             NULL,
[CategoryName]        [nvarchar](30)    NULL,
[SupplierID]          [int]             NULL,
[SupplierCode]        [nvarchar](17)    NULL,
[SupplierName]        [nvarchar](30)    NULL,
[Time]                [datetime]        NOT NULL,
[TotalQuantity]       [float]           NULL,
[ExtendedPrice]       [float]           NULL,
[ExtendedCost]        [float]           NULL`

索引定义

CREATE NONCLUSTERED INDEX [JCF_AllColumns] ON [dbo].[JCF_ItemDailySalesParent]
(
[Time]                ASC,
[ItemLookupCode]      ASC,
[StoreID]             ASC,
[ExtendedDescription] ASC,
[DepartmentID]        ASC,
[DepartmentName]      ASC,
[CategoryID]          ASC,
[CategoryName]        ASC,
[SupplierID]          ASC,
[SupplierCode]        ASC,
[SupplierName]        ASC,
[TotalQuantity]       ASC,
[ExtendedPrice]       ASC,
[ExtendedCost]        ASC
)

我使用的是 SQL Server 2012。

【问题讨论】:

  • 为什么是负分?
  • 这取决于几件事。您的硬件、您的索引方法等。您的问题没有找到最佳解决方案的线索。
  • @NimaRostami 你给负分了吗?
  • 您能否展示所涉及的表的表结构,并提供您如何创建这些索引的确切定义?另外:您使用的是哪个版本的 SQL Server? 2008, 2008 R2, 2012, 2014, 2016 ??
  • @mohamedfaisal 是的,我做到了。但我删除了它。

标签: sql-server stored-procedures query-optimization


【解决方案1】:

没有必要对每一列都进行索引,试试这个索引:

    CREATE NONCLUSTERED INDEX [JCF_AllColumns] ON [dbo].[JCF_ItemDailySalesParent]
    (
    [Time]                ASC,
    [TotalQuantity]       ASC,
    [ExtendedPrice]       ASC,
    [ExtendedCost]        ASC
    )
    INCLUDE(
    [ItemLookupCode]  ,
    [StoreID]             
)

在您的 WHERE 子句中,您不需要 CONVERT 函数,这应该可以工作。

SELECT 
    StoreID,
    ItemLookupCode,
    sum(TotalQuantity) TotalQuantity,
    sum(ExtendedPrice) ExtendedPrice,
    sum(ExtendedCost) ExtendedCost
FROM 
    [HQMatajer].[dbo].[JCF_ItemDailySalesParent]
WHERE
    time >= '20150101' AND
    time <= '20151231'
GROUP BY 
    ItemLookupCode, StoreID

[StoreID] 列是否必须为 NCHAR?除非商店 ID 的长度为 150 个字符,否则您应该将列更改为 NVARCHAR,然后重建索引。

【讨论】:

  • Incorrect syntax near the keyword 'ASC' 在这条线上INCLUDE( [ItemLookupCode] ASC, // error [StoreID] ASC )
【解决方案2】:

尝试如下创建索引:

CREATE NONCLUSTERED INDEX [JCF_foo] ON [dbo].[JCF_ItemDailySalesParent] (
    [Time],
    [StoreID],
    [ItemLookupCode]
) INCLUDE (
    [TotalQuantity],
    [ExtendedPrice],
    [ExtendedCost]
)

这应该使优化器能够使用仅索引查询。

也可以试试这个,它可以动态分组:

CREATE NONCLUSTERED INDEX [JCF_foo] ON [dbo].[JCF_ItemDailySalesParent] (
    [StoreID],
    [ItemLookupCode],
    [Time]
) INCLUDE (
    [TotalQuantity],
    [ExtendedPrice],
    [ExtendedCost]
)

【讨论】:

  • 我投赞成票,我认为我们在这个问题上浪费了时间。
【解决方案3】:

你已经创建了数据类型,你可以避免 nchar 类型。您在 StoreID 上仅存储数字。只有四位数。

[StoreID] [nchar](150) NOT NULL

将数据类型更改为 varchar(10)。 nchar 是 unicode 格式。 它会使大小翻倍。以及你把 nchar 大小为 150。即使您使用的字符不超过 4 个,这也会为所有字符创建一个内存。

由于 nchar(150) 的大小,它将在索引上创建 多个页面(不需要的 b-tree 页面)

所以改成下面的约束

[StoreID] [varchar](10) NOT NULL

并创建以下索引

CREATE NONCLUSTERED INDEX [JCF_AllColumns] ON [dbo].[JCF_ItemDailySalesParent] ( [Time] ASC, [TotalQuantity] ASC, [ExtendedPrice] ASC, [ExtendedCost] ASC ) INCLUDE( [ItemLookupCode] , [StoreID]
)

【讨论】:

  • 你的用户名怎么和提问者的一模一样?只是巧合还是你是同一个人?
  • 你怎么知道 StoreID 是 4 个字符?
猜你喜欢
  • 1970-01-01
  • 2011-08-27
  • 1970-01-01
  • 2018-01-28
  • 2015-08-11
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多