如何提高 SQL Server 中日期时间筛选的性能?

Posted

技术标签:

【中文标题】如何提高 SQL Server 中日期时间筛选的性能?【英文标题】:How to improve performance for datetime filtering in SQL Server? 【发布时间】:2013-06-29 15:42:31 【问题描述】:

我在按datetime 列过滤时遇到问题。

我试过这两种方法:

datefield < '2013-03-15 17:17:55.179'
datefield < CAST('2013-03-15 17:17:55.179' AS datetime)

我有一个包含 3.000.000 多个主要对象的大型数据库。

所以我需要提高datetime 过滤的性能。我正在阅读有关 UNIX 时间戳的信息(将所有 datetime 转换为 UNIX 时间戳,然后按此 UNIX 字段进行过滤)。

我认为这比通过datetime 过滤更好。但如果有人知道其他方式,我将不胜感激。

我的查询是:

SELECT TOP (100)  ev.Title as Event_name, po.Name as POI_name, 
po.Address, po.City, po.Region, po.Country, po.Latitude, po.Longitude, ev.Start_time, 
(Select ID_Category FROM SubCategory s where ev.ID_SubCategory = s.ID_SubCategory) as ID_Category, 
ev.ID_SubCategory, ev.ID_Event, ev.ID_Channel, IDChanelEvent, 
ev.FavoriteCount, po.gmtOffset, v.IsFavorite, v1.IsFavorite  
FROM Events ev 
JOIN POI po ON ev.ID_POI = po.ID_POI 
JOIN (SELECT et.id_event as joinIdEv FROM EventTagLink et, tags t 
 WHERE t.id_tag = et.id_tag 
 AND ( t.Title = N'music' ) 
 ) as joinEvents 
 ON joinEvents.joinIdEv = ev.ID_Event 
LEFT JOIN Viewed v ON v.ID_Event = ev.ID_Event AND v.ID_User = 1 AND v.IsFavorite = 1 LEFT join Viewed v1 ON v1.ID_Event = ev.ID_Event AND v1.ID_User = 1 AND v1.IsFavorite = 0
WHERE 
--ev.GmtStop_time > '2013-03-15 14:17:55.188' AND 
po.Latitude > 41.31423 AND po.Latitude < 61.60511 
AND  po.Longitude > -6.676602 AND po.Longitude < 17.04498  
AND ev.ID_SubCategory in (3, 12, 21, 4, 30, 13, 22, 6, 14, 40, 23, 7, 32, 15, 41, 8, 50, 33, 16, 42, 25, 9, 34, 17, 35, 18, 44, 27, 36, 19, 45, 28, 37, 46, 29, 38, 47, 39, 48, 49, 10, 1, 11, 2, 20) 
--AND ev.GmtStart_time< '2013-03-15 17:17:55.179'
AND v1.IsFavorite is null

按我发表评论的时间过滤。

如果我关闭这些过滤器,请求持续时间是几秒钟。如果我打开它们,那么请求持续时间超过 25 秒。

Execution plan with filtering datetime Execution plan without datetime filter

所以有很多关于执行计划、索引等的讨论。但是 UNIX 时间戳 呢,这是我提出问题的主要原因。 会提高datetime 过滤的性能吗?

提前致谢。

【问题讨论】:

datefield 列上是否有索引? 首先:确保您在该列上有相关索引。其次:不要在WHERE 表达式中的日期时间列上使用任何函数(如CAST 是的。有帮助,但还不够 这里没有足够的信息来了解问题所在。您需要展示整个 SQL,然后告诉我们您对它的期望,即。您希望它返回多少行,您希望/希望它消耗多少时间,它实际消耗多少时间,等等。 根据您的标准匹配的 300 万行中的 多少 行,它不会过滤太多 - 但这与“unix 时间戳”完全一样过滤或其他。如果您查询要求 20%、50% 的数据 - 它会总是很慢。这里没有灵丹妙药...... 【参考方案1】:

关于 msql 中日期时间索引的建议是索引占用空间会影响搜索时间(是的,这似乎很明显......但请继续阅读)。

在日期时间编制索引时对此的重要性例如“2015-06-05 22:47:20.102”,索引必须考虑到日期时间内的每个位置。这在空间上变得非常大并且笨重。我采用的一种成功方法是创建一个新的 datetime 列并通过将时间四舍五入到小时来填充数据,然后在这个新列上构建索引。示例“2015-06-05 22:47:20.102”转换为“2015-06-05 22:00:00.000”。通过采用这种方法,我们可以单独保留详细数据,并可以通过在这个新列上搜索来显示或使用它,这为我们提供了大约 10 倍(至少)返回结果的速度。这是因为索引不必考虑分钟、秒和毫秒字段。

【讨论】:

您的回答让我进行了调查,我可以通过使用 [datetimeoffset](0) 将 datetimeoffset 精度降低到秒(删除毫秒)来提高性能。 ***.com/a/2247898/507699 BTREE 索引,在任何数据类型上,都具有 O(size * log(size)) 的空间复杂度,其中 size 是被索引的数据量。更高的精度值会导致索引大小过度膨胀的想法是不正确的。 @Sean 有什么证据吗?为什么木指数关心时间价值里面有什么?它只关心 =, . 我认为在几乎所有情况下索引包括时间在内的日期都是一个坏主意。它本质上是说,在涉及该字段的任何搜索条件中,您永远不会得到完全匹配。我建议有两个字段,一个用于日期,一个用于时间,并对它们进行索引。然后您的日期搜索将始终找到完全匹配,让您更快地找到相关数据。然后您可以在该数据集中过滤时间。 更改索引键的粒度不会更改索引中的行数,这主要决定了索引的大小。仅当您另外应用页面压缩时,索引大小本身才会显着减小,即使这样,大小的减小也只会对索引扫描而不是搜索显着。作为一个思考练习,想象一个只存储年份的索引(因此将所有行“四舍五入”到2015,但仍然必须索引所有行),看看为什么这并没有真正帮助。如果一个全新的索引“有帮助”,很可能只是因为旧索引是零散的。【参考方案2】:

您需要先查看您的执行计划,以了解 SQL Server 正在做什么。很可能,您只需要添加一个索引。像这样的小转换几乎从来都不是您的查询缓慢的原因。索引是修复查询的良好第一站。

您不需要将其设为聚集索引。使其成为聚集索引意味着您不需要进行查找,但对于仅 100 行,查找速度非常快。我会按顺序将日期时间和子类别放入非聚集索引中。

如果您正在订购,您还应该确保它在索引中。由于每个表只使用一个索引才有意义,因此您需要确保所有相关列都在同一个索引中,并且顺序正确。

但首先,获得你的实际执行计划!

【讨论】:

2.在主表中,我有很多索引,执行计划是问我的。每个索引都有一些包含的列。你怎么想。我应该把它们结合起来吗? 您可以在问题中发布计划吗?我会从没有包含的列开始,如果您认为性能很差,然后将它们包含在内。包含的列增加了索引的维护,每次向表中添加列时都需要修改。除非查找时间很长,否则我不会包含它们。 我添加到问题执行计划。看看吧 @SashaFencyk 这很有趣。查询中最昂贵的部分是 Index Seeks 和 RID Lookup。此外,总数大于100%。我不明白这怎么会慢 25 倍。运行时间是否始终慢 25 倍?您还可以发布原始查询的执行计划吗?是否发生了一些锁争用? 您对索引的看法是正确的。我只是要把它们扔到左边和中间。我接受了你的建议,做了一个执行计划,并意识到查询是即时的……更多的挖掘导致了一系列非常糟糕的垃圾……优化了一切,一切又像梦一样运行。没有添加索引! +1 +啤酒【参考方案3】:

为了获得更好的性能,我建议您创建新索引:

CREATE INDEX x1 ON LiveCity.dbo.Tags(Title) INCLUDE(ID_Tag)
CREATE INDEX x2 ON LiveCity.dbo.Tags(ID_Event, GmtStart_time, GmtStop_time) 
  INCLUDE(
          FavoriteCount, 
          ID_Channel, 
          ID_POI, 
          ID_SubCategory, 
          IDChanelEvent, 
          Start_time, 
          Title
          )
CREATE INDEX x ON LiveCity.dbo.POI(ID_POI, Latitude, Longitude) 
  INCLUDE(
          Address, 
          City, 
          Country, 
          gmtOffset, 
          Name, 
          Region
          )

这将帮助您避免 RID 查找操作并提高查询的整体性能。

【讨论】:

【参考方案4】:

试试这个 -

;WITH cte AS (
     SELECT IsFavorite, ID_Event  
     FROM Viewed
     WHERE ID_User = 1 
)
SELECT TOP (100)
      Event_name = ev.Title 
    , POI_name = po.Name 
    , po.[address]
    , po.City
    , po.Region
    , po.Country
    , po.Latitude
    , po.Longitude
    , ev.start_time
    , s.ID_Category
    , ev.ID_SubCategory
    , ev.ID_Event
    , ev.ID_Channel
    , IDChanelEvent
    , ev.FavoriteCount
    , po.gmtOffset
    , v.IsFavorite
    , IsFavorite = NULL
FROM [events] ev
JOIN POI po ON ev.ID_POI = po.ID_POI
LEFT JOIN SubCategory s ON ev.ID_SubCategory = s.ID_SubCategory
LEFT JOIN cte v ON v.ID_Event = ev.ID_Event AND v.IsFavorite = 1
WHERE po.Latitude BETWEEN 41.31423 AND 61.60511
     AND po.Longitude BETWEEN -6.676602 AND 17.04498
     AND ev.ID_SubCategory IN (3, 12, 21, 4, 30, 13, 22, 6, 14, 40, 23, 7, 32, 15, 41, 8, 50, 33, 16, 42, 25, 9, 34, 17, 35, 18, 44, 27, 36, 19, 45, 28, 37, 46, 29, 38, 47, 39, 48, 49, 10, 1, 11, 2, 20)
     AND v1.IsFavorite IS NULL
     AND EXISTS(
          SELECT 1 
          FROM EventTagLink et
          WHERE t.Title = 'music'
               AND et.joinIdEv = ev.ID_Event
     )
     AND NOT EXISTS (
          SELECT * 
          FROM cte v1 
          WHERE v1.ID_Event = ev.ID_Event AND v1.IsFavorite = 0
     )

【讨论】:

【参考方案5】:

在日期时间字段上创建集群索引肯定会有所帮助。我们之前遇到了同样的问题。我们通过在 datetime 列上创建索引来解决它。

【讨论】:

是的,集群索引将比非集群索引提供更好的性能,因为最终非集群索引在内部使用集群索引。你能给我样本数据库吗?我想玩它。我真的有兴趣做这类事情。 认真的吗? @SashaFencyk,不要让这里的人直接访问您的数据到您的服务器。 感谢@MikeSherrill'Catcall' 的关心。我明白)

以上是关于如何提高 SQL Server 中日期时间筛选的性能?的主要内容,如果未能解决你的问题,请参考以下文章

sql server 数据库,在查询sql语句中日期格式转换问题,怎么把原数据年月日时分秒转换成年月日

利用 SQL Server 过滤索引引提高查询语句的性能

SQL between and 日期范围 筛选数据不符

sql server2000如何将数字转换为日期时间

Java开发小白求助,筛选日期有关问题?

如何通过linqdatasource的where筛选日期在某时间段的记录?