【问题标题】:Improving performance of UPDATE query with subqueries使用子查询提高 UPDATE 查询的性能
【发布时间】:2017-06-18 20:17:55
【问题描述】:

我有一张邮政编码表,其中包含美国和加拿大的邮政编码和相关信息 - 包括纬度和经度。

我有一些记录从我无法修改的单独应用程序插入到表中。这些记录缺少纬度和经度数据,所以我想相应地填充记录。 (在有人问之前,由于性能原因,在运行时与 ZipCodes 表进行 JOIN 似乎不是一种选择,这就是为什么我最终走到了现在的位置。)

我有如下所示的查询,它被设置为作为计划任务运行,它应该更新任何尚未查找其地理数据的记录。此查询(一次 100 个)运行大约需要 1m 35s。

我正在寻找我在这里所做的任何和所有选择,这可能会提高性能。

我采用了计划任务,因为我担心整个服务器会因为 INSTEAD OF INSERT 或 AFTER INSERT 触发器而瘫痪以执行相同的操作……但这本来是我的偏好。鉴于当前的性能问题,触发器似乎是不可能的。

ZipCodes 表在 CityName 和 ProvinceAbbr 上有一个非聚集索引,另外还包含 PostalCode、Latitude 和 Longitude 列。我将允许行锁定和允许页面锁定设置为 false。此表中的数据可能每季度更改一次,因此脏读没问题。

如有必要,我可以提供执行计划结果...但不确定如何准确提示我如何生成复制/粘贴材料。 =D

ZipCodes 表有 947,172 条记录,LoadsAvail 表在任何给定时间都有大约 38k 条记录...记录被实时/不断地插入、更新和删除,有时是大批量(我会说最大一次插入 20 个,通常更像是一次插入一两个)。

一旦大多数记录都有自己的地理数据,每分钟更新的记录可能少于 100 条,但我想知道是否有更好的方法来完成这一切。

UPDATE TOP (100)
    LoadsAvail

SET
    coordinatesChecked = 1,
    FromLatitude =  (   SELECT TOP (1) Latitude
                                        FROM ZipCodes AS ZipCodes_1 WITH(NOLOCK)
                                        WHERE (CityName = loadsavail.FromCity) AND (ProvinceAbbr = loadsavail.FromState)
                                    ),
    FromLongitude = (   SELECT TOP (1) Longitude
                                        FROM ZipCodes AS ZipCodes_2 WITH(NOLOCK)
                                        WHERE (CityName = loadsavail.FromCity) AND (ProvinceAbbr = loadsavail.FromState)
                                    ),
    ToLatitude =    (   SELECT TOP (1) Latitude
                                    FROM ZipCodes AS ZipCodes_3 WITH(NOLOCK)
                                    WHERE        (CityName = loadsavail.ToCity) AND (ProvinceAbbr = loadsavail.toState)
                                ),
    ToLongitude =   (   SELECT TOP (1) Longitude
                                    FROM ZipCodes AS ZipCodes_4 WITH(NOLOCK)
                                    WHERE        (CityName = loadsavail.ToCity) AND (ProvinceAbbr = loadsavail.toState)
                                )
WHERE
    coordinatesChecked = 0

【问题讨论】:

  • 是的,我读到了。这似乎是对 NOLOCK 的恰当使用 - 一个用作查找表的表,包含大量数据,每个日历季度可能更改一次?
  • 如果数据不那么频繁地更改,那么是的,该提示可能不会伤害任何东西......但它也不太可能有帮助,因为数据不会锁定。 :)
  • 明白...谢谢!
  • 如果 (CityName, ProvinceAbbr) 不是唯一的,您可以从与经度不同的城市获取纬度。你知道吗?

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


【解决方案1】:

您可以使用 Joins 代替 子查询

UPDATE T1
SET T1.coordinatesChecked = 1,
    T1.FromLatitude =  T2.Latitude,
    T1.FromLongitude = T2.Longitude
    T1.ToLatitude =    T3.Latitude,
    T1.ToLongitude =   T3.Longitude
FROM            LoadsAvail AS T1 LEFT JOIN ZipCodes AS T2 ON T1.FromCity = T2.CityName AND T1.FromState = T2.ProvinceAbbr
                                 LEFT JOIN ZipCodes AS T3 ON T1.toCity = T3.CityName AND T1.toState = T3.ProvinceAbbr
WHERE    T1.coordinatesChecked = 0

【讨论】:

  • 如果为 CityName 和 ProvinceAbbr 找到多个记录,这会起作用吗?由于它是一个邮政编码数据库,一个城市/州的组合通常有多个邮政编码。你觉得这个查询会更快吗?
  • 是的,我会工作,你可以检查查询执行计划。我认为这种方法比为每行更新执行 4 个子查询要好
  • 检查执行计划给我们反馈就好了
  • will this work if more than one record is found for CityName and ProvinceAbbr 但所选值没有规则(如果找到多个)
  • 没有规则,因为如果找到多个,使用哪一个并不重要。因此,其中包含 top 1 的子查询。但是,是的,这工作得很好,好多了!是的,任何事情都比执行四个子查询要好 =D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 2021-11-14
  • 2012-02-03
  • 2013-08-03
相关资源
最近更新 更多