【问题标题】:What is the most efficient way to correlate a subquery on a big table in T-SQL?在 T-SQL 中关联大表上的子查询的最有效方法是什么?
【发布时间】:2019-04-15 20:54:08
【问题描述】:

我有一个表,其中包含机器销售的品牌、型号、序列号和发票日期,我想将它与包含品牌、序列号、记录使用情况、使用单位和记录日期的表配对 -除了使用/记录表是 HUUUUUUGE 并且可能没有每台机器的记录。

我已尝试编写 OUTER JOIN,但 Usage/Records 表中的数据过多,无法使其高效运行。我试着写一个 CROSS APPLY,但我一定是搞砸了,因为这似乎也不是很有效。

文件示例:

我的基本查询:

Inv. Date      Mk      Model      Serial
2019-03-29     AA      420D       0FDP09999
2019-03-21     AA      A19B-SSL   0DX240481

使用/记录表:

Mk      Serial      Usage      Units      Record Date
AA      0FDP09999   2345.0     H          2019-03-27
AA      0FDP09999   2349.2     H          2019-03-28
AA      0FDP09999   2351.8     H          2019-03-29
AA      0DX240481   0.0        H          2019-03-21
AA      0DX240481   24.0       H          2019-03-22

输出应该是:

Inv. Date      Mk      Model      Serial      Usage      Units      Record Date
2019-03-29     AA      420D       0FDP09999   2351.8     H          2019-03-29
2019-03-21     AA      A19B-SSL   0DX240481   0.0        H          2019-03-21

...仅返回发票日期之前的最新条目的使用、单位和记录日期。

有什么建议吗?

【问题讨论】:

  • 请参阅paste the plan,了解在您的问题中包含执行计划的方法。模式和查询也会有所帮助。
  • 如何加入表格?在Serial 列上?如果是,那么要让CROSS APPLY(或者更确切地说是OUTER APPLY)有效地工作,您需要一个合适的索引。在您的情况下,它看起来像这样:ON (Serial, RecordDate) INCLUDE (Usage, Units)INCLUDE 部分是可选的,大部分性能都是通过搜索该索引获得的。
  • Last_Value 可能有点用处。

标签: sql-server tsql correlated-subquery


【解决方案1】:

您可以尝试左连接和row_number()

SELECT t1.[Inv. Date],
       t1.[Mk],
       t1.[Model],
       t1.[Serial],
       t2.[Usage],
       t2.[Units],
       t2.[Record Date]
       FROM (SELECT t1.[Inv. Date],
                    t1.[Mk],
                    t1.[Model],
                    t1.[Serial],
                    t2.[Usage],
                    t2.[Units],
                    t2.[Record Date],
                    row_number() OVER (PARTITION BY t1.[Inv. Date]
                                       ORDER BY t2.[Record Date] DESC) rn
                    FROM table1 t1
                         LEFT JOIN table2 t2
                                   ON t2.[Mk] = t1.[Mk]
                                      AND t2.[Serial] = t1.[Serial]
                                      AND t2.[Record Date] <= t1.[Inv. Date]) x
       WHERE x.rn = 1;

为了提高性能,请尝试在第一个表的 ([Mk], [Serial], [Inv. Date]) 和第二个表的 ([Mk], [Serial], [Record Date]) 上创建索引。或者,如果连续剧在不同品牌上或多或少“独特”,则可以尝试切换 [Mk][Serial] 的位置。

【讨论】:

  • 我最终使用了这个答案的修改版本。这绝对有助于让我朝着正确的方向思考。非常感谢!
【解决方案2】:

为了解决这个问题,我最终在最初的基本查询之外创建了额外的查询。

在第一个外部查询中,我执行了此操作(“发票编号”是我调用的一个附加字段,以确保唯一的行编号,以防机器在该时间段内被出售一次、买回并再次出售):

CASE
    WHEN Q1.[Usage] IS NULL
    THEN 1
    ELSE ROW_NUMBER() OVER (PARTITION BY Q1.[Serial Number], Q1.[Mk], Q1.[Invoice Number] ORDER BY Q1.[Record Date] DESC)
END AS [RowNum]

这可确保表中的每个条目都有排序机制,即使连接表中没有使用情况测量。

然后,下一个外部查询只抓取 RowNum = 1 的行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 2018-05-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    相关资源
    最近更新 更多