有什么办法可以加快这个大型全表查询的速度吗?

dat*_*000 4 sql-server query-performance

我有一个查询,它只从一张表和一个WHERE过滤器中进行选择。然而,它需要很长时间来执行,甚至偶尔会超时。这可能是因为它从 1300 万行(其他 900 万条记录早于 2019 年)的表中过滤掉了大约 400 万行,并且它返回了所有列,其中有 101 列(混合了datetimevarchar, 和int列)。它有两个索引,一个聚集在其主键上interaction_id的索引,和一个非聚集索引,interaction_date其上的日期时间列是主过滤器。这是查询:

  SELECT * 
  FROM [Sales].[dbo].[Interaction] 
  WHERE 
  year(Interaction_date) >= 2019
Run Code Online (Sandbox Code Playgroud)

通过添加/调整索引或调整查询本身,我可以做些什么来提高此查询的性能?在我进入 ETL 过程或反击需要此查询的组之前(他们是一个 Hadoop sqooping 团队,他们坚持认为他们需要一直使用所有列对所有这些记录进行 sqoop),我想看看我是否作为 DBA,我可以通过做一些事情来让人们更轻松。

默认情况下,查询计划会忽略我在interaction_date列上的非聚集索引,并且仍然执行完整的聚集索引扫描。所以我然后尝试通过包含WITH (INDEX(IX_Interaction_Interaction_Date))在选择中来强制它使用它。

这迫使它以非聚集索引的索引扫描开始进入查询计划,估计行数为 400 万,但估计行读取为所有 1300 万。然后在很短的时间之后,它会将剩余的执行时间花在主聚集索引的键查找上。

但最终,它似乎根本没有加快查询速度。

Dav*_*oft 14

通过添加/调整索引或调整查询本身,我可以做些什么来提高此查询的性能?

是的。首先使谓词sargable

SELECT * FROM 
[Sales].[dbo].[Interaction] 
WHERE Interaction_date >= '20190101'
Run Code Online (Sandbox Code Playgroud)

然后考虑分区,或包含列的过滤索引。但即使您有一个索引可以支持此查询作为简单的搜索+扫描,将所有列发送到客户端也需要时间。


Nza*_*all 10

注意:我不打算对查询本身发表评论,但考虑到此查询的大小,我将讨论一些也会对此产生影响的内容。

一些基本的数学计算,假设 varchar 列中数据的平均大小为 30 个字符,并且列大致分为 3 种类型:

101 列 * ((30+8+4)/3) = 每列 14 字节 * 4,000,000 行 = 大约 56 亿字节

略多于 5 GB 的空间,仅用于数据(以全尺寸传输大约需要 86,500 个 UDP 数据包)。考虑到每列的平均字节数可能明显高于 14 字节,这可能是一个保守的估计。每列每增加一个平均字节,就需要额外增加 400 MB 的数据传输。

根据您的连接并假设没有其他流量的直接连接,这将需要 40 秒(假设为千兆以太网)到 400 秒,或几乎 7 分钟,使用 100Mbit 以太网纯粹用于此数据。任何额外的延迟、线路上的数据流量或其他干扰也会影响所需的时间。

我知道您的客户正在使用 Hadoop 和 Sqoop,但我说的是连接的物理限制,而软件对此无能为力。查询花费的大部分时间完全有可能只是将它从您的 SQL 服务器获取到您的 Hadoop 系统。您可以通过尝试手动将 5.6 GB 文件从 SQL 服务器复制到运行 Hadoop 的任何设备来检查这有多大影响。这将很好地估计您的查询从 SQL 机器移动到 Hadoop 机器所需的时间。