3

总体挑战:

我们每天为多个“市场”添加数次商品。

所以

  • 在 12:00 我们为市场“x”添加 2000 个项目
  • 在 12:30 我们为市场“y”添加 3000 个项目
  • 在 14:00 我们再次为市场“x”添加 2500 个项目

每天进行几次。

在任何给定时间,我们都需要每天为每个市场提取最新项目

上述插入的期望结果是

市场“x”的 2500 个项目

市场“y”的 3000 个项目

一批数据的每次添加都有一个 ExecutionTime 时间戳,该时间戳唯一地定义了该批。因此,市场“x”在 12:00 的 2000 个项目将具有相同的 ExecutionTime 值,而市场“x”在 14:00 的 2500 个项目将具有另一个 ExecutionTime 值。

我们为我们创建了一个视图

SELECT     
    *
FROM         
    dbo.Items AS s
WHERE     
    (ExecutionTime =
       (SELECT     MAX(ExecutionTime) AS Expr1
        FROM          dbo.Items AS s2
        WHERE      (SiteAlias = s.SiteAlias) AND (Market = s.Market) 
          AND (LocalTimestamp >= 
            DATEADD(dd, DATEDIFF(dd, 0, s.LocalTimestamp), 0)) 
          AND 
              (LocalTimestamp < 
            DATEADD(dd, DATEDIFF(dd, 0, s.LocalTimestamp), 1))))

我们这样查询视图:

SELECT *
FROM [ExportedData]
WHERE 
  SiteAlias = 'MyAlias'
  AND LocalTimeStamp between '2012-05-14 00:00' AND '2012-05-18 00:00'
ORDER BY [Timestamp]

我们在执行时间字段上定义了表 ITems 上的索引,并在 sitealias、marked 和 localtimestamp 上定义了组合索引。

问题:性能很差。查询大约 150000 行需要几分钟时间。

我们应该做的视图有什么明显的改进吗?我已经准备好提供查询计划等 - 以防我们在创建视图时没有简单的搞砸。

有趣的是,如果我们在 SiteAlias 上使用“LIKE”而不是“=”来查询视图,它会加快大约 90% 的执行速度——这是我没有预料到的。

谢谢,

:o)

/杰斯珀哥本哈根

4

2 回答 2

3

乍一看,您的 T-SQL 和表结构对我来说还不错 - 所以这只是暗中的狂野 :-)

由于您使用的是 SQL Server 2008,因此我可能会尝试使用 CTE(公用表表达式)并转换LocalTimestamp为数据类型。DATE

有了这些,您可以让您的视图类似于:

CREATE VIEW dbo.YourView
AS
   WITH DataPerDay AS
   (
      SELECT 
         *,
         RowNum = ROW_NUMBER() OVER (PARTITION BY CAST(LocalTimestamp AS DATE) 
                                     ORDER BY ExecutionTime DESC)
      FROM         
         dbo.Items AS s
   )
   SELECT *
   FROM DataPerDay 
   WHERE RowNum = 1

基本上,CTE 按仅日期部分“分区”您的数据,LocalTimestamp然后将序列号分配给当天的所有条目,从 1 开始 - 所以每天的“最新”或“最近”条目RowNum = 1就是我在从该 CTE 中选择时使用。

这绕过了SELECT(MAX) ....子查询,在我个人的观察中似乎要快一点——但这在很大程度上取决于你的表和数据——所以你自己试试看是否有帮助!

于 2012-05-25T09:27:03.300 回答
2

有趣的是,如果我们在 SiteAlias 上使用“LIKE”而不是“=”来查询视图,它会加快大约 90% 的执行速度——这是我没有预料到的。

嗯,确实很奇怪。这可能是潜在问题的结果。

查询是否一直很慢或性能问题是否在一段时间后开始。您可以在查询末尾添加 OPTION (RECOMPILE) 以便我们可以排除“参数嗅探”吗?

SELECT *
FROM [ExportedData]
WHERE 
  SiteAlias = 'MyAlias'
  AND LocalTimeStamp between '2012-05-14 00:00' AND '2012-05-18 00:00'
ORDER BY [Timestamp]
OPTION (RECOMPILE)

您是说该表每天添加几次。SQL Server 通常在使统计信息保持最新方面做得很好,但优化器可能使用错误/数据不足的统计信息

  • 是否为此数据库设置了 AUTO_CREATE_STATISTICS?
  • 您能否隔离一个执行缓慢的查询实例并在刷新所有统计信息后让它运行?

最好看到类似的执行计划和查询的 = 版本。

更新 1

你给出了估计的执行计划的截图。我们需要查看实际(包括估计)。此外,屏幕截图的第二个链接不起作用。

您能否使用 xml 计划更新问题,而不是将它们放入评论中。这对新人看问题也更有帮助。

我不明白“=”版本的执行计划说,当估计的行数为 1 时,100% 进入键查找。这没有意义

实际执行的 xml 计划肯定会有所帮助。您可以查看实际行数和估计行数之间的差异,因为基数可能会关闭。在这种情况下使用临时表可能会有所帮助,因为统计信息是准确的,并且您可以在其上放置索引

SELECT *
into #tempExportedData
FROM [ExportedData]

SELECT *
FROM #tempExportedData
WHERE 
  SiteAlias = 'MyAlias'
  AND LocalTimeStamp between '2012-05-14 00:00' AND '2012-05-18 00:00'
ORDER BY [Timestamp]
于 2012-05-25T09:18:00.863 回答