请求优化

时间:2021-07-02 08:51:02

标签: sql tsql

我有两张桌子,一张桌子上有公共汽车参加的所有比赛

dbo.Courses_Bus
|ID|ID_Bus|ID_Line|DateHour_Start_Course|DateHour_End_Course|

另一方面,在这些公交车上支付的所有款项

dbo.Payments
|ID|ID_Bus|DateHour_Payment|

目标是在支付表中添加 Line 的概念以获得类似的内容

dbo.Payments
|ID|ID_Bus|DateHour_Payment|Line|

所以我尝试这样做:

/** I first added a Line column to the dbo.Payments table**/
UPDATE
    Table_A
SET
    Table_A.Line = Table_B.ID_Line
FROM
    [dbo].[Payments] AS Table_A
    INNER JOIN [dbo].[Courses_Bus] AS Table_B
        ON Table_A.ID_Bus = Table_B.ID_Bus
          AND Table_A.DateHour_Payment BETWEEN Table_B.DateHour_Start_Course AND Table_B.DateHour_End_Course

还有这个

UPDATE 
  Table_A 
SET 
  Table_A.Line = Table_B.ID_Line 
FROM 
  [dbo].[Payments] AS Table_A 
  INNER JOIN (
    SELECT
      P.*, 
      CP.ID_Line AS ID_Line
    FROM
      [dbo].[Payments] AS P 
      INNER JOIN [dbo].[Courses_Bus] CP ON CP.ID_Bus = P.ID_Bus
      AND CP.DateHour_Start_Course <= P.Date 
      AND CP.DateHour_End_Course >= P.Date
  ) AS Table_B ON Table_A.ID_Bus = Table_B.ID_Bus

除了这些请求似乎无法正常工作之外,主要问题是每个表都有几百万行并且每天都在增加,并且由于 datehour 过滤器(因为可以使用单个总线,因此必须使用)每天几行)SSMS 必须将第二个表的每一行与另一个表的所有行进行比较。

所以它需要无限量的时间,而且每天都会增加。

我怎样才能让它工作并优化它?

2 个答案:

答案 0 :(得分:0)

假设这是你想要的逻辑:

UPDATE p
    SET p.Line = cb.ID_Line
    FROM [dbo].[Payments] p JOIN
         [dbo].[Courses_Bus] cb
          ON p.ID_Bus = cb.ID_Bus AND
             p.DateHour_Payment BETWEEN cb.DateHour_Start_Course AND cb.DateHour_End_Course;

要优化此查询,您需要在 Courses_Bus(ID_Bus, DateHour_Start_Course, DateHour_End_Course) 上建立索引。

可能有稍微更有效的方法来优化查询,但您的问题没有足够的信息——例如,是否总是有一个匹配项?

另一个大问题是更新所有行非常昂贵。您可能会发现最好在循环中执行此操作,一次一个块:

UPDATE TOP (10000) p
    SET p.Line = cb.ID_Line
    FROM [dbo].[Payments] p JOIN
         [dbo].[Courses_Bus] cb
          ON p.ID_Bus = cb.ID_Bus AND
             p.DateHour_Payment BETWEEN cb.DateHour_Start_Course AND cb.DateHour_End_Course
    WHERE p.Line IS NULL;

再一次,这个结构依赖于所有的初始值是 NULL 和所有行的精确匹配。

答案 1 :(得分:0)

感谢戈登的回答。

我已经调查并提出了这个查询:

MERGE [dbo].[Payments] AS p 
USING [dbo].[Courses_Bus] AS cb 
ON p.ID_Bus= cb.ID_Bus AND
             p.DateHour_Payment>= cb.DateHour_Start_Course AND 
             p.DateHour_Payment<= cb.DateHour_End_Course
WHEN MATCHED THEN 
UPDATE SET p.Line = cb.ID_Ligne;

因为它似乎最适合 MS-SQL 环境。

它也带来了错误:

The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.

我理解这意味着它找到了几行相同的行

[p.ID_Bus= cb.ID_Bus AND
p.DateHour_Payment >= cb.DateHour_Start_Course AND 
p.DateHour_Payment <= cb.DateHour_End_Course]

是的,这是一种可能的情况,但 ID 每次都不同。 例如,如果两个蓝卡同时发出哔哔声,或者如果网络丢失且设备已更新,则发出哔哔声。这些是必须分开处理的不同行,您可以获取例如:

|ID|ID_Bus|DateHour_Payments|Line| 
----------------------------------
|56|204|2021-01-01 10:00:00|15|
----------------------------------
|82|204|2021-01-01 10:00:00|15|

如何改进此查询以使其考虑不同的付款 ID?

我无法在网上找到的帮助下弄清楚如何做到这一点。在这种情况下,这种方法可能不是正确的方法。