【问题标题】:Optimize performance on SQL table - indexing优化 SQL 表的性能 - 索引
【发布时间】:2017-04-16 02:02:32
【问题描述】:

我的数据库中有一个包含 500 万条记录的表:

CREATE TABLE [dbo].[PurchaseFact](
    [Branch] [int] NOT NULL,
    [ProdAnal] [varchar](30) NULL,
    [Account] [varchar](12) NULL,
    [Partno] [varchar](24) NULL,
    [DteGRN] [date] NULL,
    [DteAct] [date] NULL,
    [DteExpect] [date] NULL,
    [OrderNo] [bigint] NULL,
    [GRNNO] [varchar](75) NULL,
    [SuppAdv] [varchar](75) NULL,
    [Supplier] [varchar](12) NULL,
    [OrdType] [varchar](4) NULL,
    [UnitStock] [varchar](4) NULL,
    [OrderQty] [float] NULL,
    [RecdQty] [float] NULL,
    [Batch] [varchar](100) NULL,
    [CostPr] [float] NULL,
    [Reason] [varchar](2) NULL,
    [TotalCost] [float] NULL,
    [Magic] [bigint] IDENTITY(1,1) NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [Magic] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

从上面可以看出 - CLUSTERED INDEX 被用于 MAGIC 列,这是一个 UNIQUE 列。

以下SELECT statement 的数据检索时间超过 8 分钟,导致报告问题:

SELECT Branch,
    Supplier,
    ProdAnal,
    DteGRN AS Date,
    PartNo AS Partno,
    OrderNo,
    OrderQty,
    TotalCost,
    CostPr
FROM dbo.PurchaseFact src
WHERE YEAR(DteGRN) = 2016

排除WHERE clause 也不会使查询运行得更快。 我已经尝试与CLUSTERED index 一起包含UNIQUE index,希望它运行得更快但无济于事:

CREATE UNIQUE INDEX Unique_Index ON dbo.PurchaseFact ([Branch], [Supplier], [Magic]) 
INCLUDE ([ProdAnal], [Account], [Partno], [DteAct], [DteExpect], [OrderNo], [GRNNO], 
[SuppAdv], [OrdType], [UnitStock])

有什么方法可以优化此表的性能时间,还是应该求助于归档旧数据?

任何建议将不胜感激。

【问题讨论】:

  • 2016 年返回了多少行?数据传输可能需要一些时间。
  • 您可以添加一个持久计算列来进行当年的计算吗?然后,您可以在该字段上添加一个非聚集索引并包含其他索引。
  • @jarlh - 返回 160 万条记录。
  • 您可以尝试在 DteGRN 和 = 谓词上使用索引来选择年内的数据。
  • 我看到两个问题:首先,您的原始查询未使用索引(因此未使用全表扫描)。其次,您正在操纵年份(提取 YEAR 部分)。我建议您更改此设置并改用WHERE DteGRN >= '2016-01-01' and DteGRN < '2017-01-01'(或替代BETWEEN 格式)。

标签: sql sql-server performance indexing sql-server-2014


【解决方案1】:

这是你的where 子句:

WHERE YEAR(DteGRN) = 2016

如果表有 500 万行,那么这将返回大量数据,假设任何合理的日期分布。数据量可能与查询的时间长度有关。

您可以做的一件事是改写WHERE,然后在相应的列上放置一个索引:

WHERE DteGRN >= '2016-01-01' and DteGRN < '2017-01-01'

这可以利用PurchaseFact(DteGRN) 上的索引。但是,考虑到可能返回的行数,索引可能不会有太大帮助。

更大的问题是,为什么您的报告应用程序要恢复 2016 年的所有行,而不是在数据库中汇总它们。我怀疑您的报告应用程序存在架构问题。

【讨论】:

  • 感谢 Gordon - 这无疑有助于加快速度。从 8:44 分钟到 2:50 分钟。
【解决方案2】:

抱歉,无法添加 cmets。

为了帮助进一步提高性能(如果您可以忍受 UPDATE 开销),请创建一个仅包含查询 SELECT 部分中的列的 COVERING INDEX。

【讨论】:

    猜你喜欢
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    相关资源
    最近更新 更多