在 T-SQL 中的大 table 上关联子查询的最有效方法是什么?
What is the most efficient way to correlate a subquery on a big table in T-SQL?
我有一个 table,其中包含机器销售的制造商、型号、序列号和发票日期,我想将其与包含制造商、序列号的 table 配对,记录的使用情况、使用单位和记录日期 - 除了 Usage/Record Table 是 HUUUUUUGE 并且可能没有每台机器的记录。
我试过编写一个 OUTER JOIN,但是 Usage/Record 中的数据太多 table,无法有效地运行。我试着写了一个 CROSS APPLY,但我一定是搞砸了,因为那似乎也不是很有效。
文件示例:
我的基本查询:
Inv. Date Mk Model Serial
2019-03-29 AA 420D 0FDP09999
2019-03-21 AA A19B-SSL 0DX240481
Usage/Records Table:
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
...仅返回发票日期之前的最新条目的使用情况、单位和记录日期。
有什么建议吗?
您可以尝试左连接和 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])
上的索引 table。或者,如果连续剧或多或少 "unique" 也超过不同品牌,则可以尝试切换 [Mk]
和 [Serial]
的位置。
为了解决这个问题,我最终在最初的基本查询之外创建了额外的查询。
在第一个外部查询中,我这样做了("Invoice Number" 是我调用的一个附加字段,以确保唯一的行编号,以防机器被出售一次,买回,然后再次出售时间段):
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]
这确保 table 中的每个条目都有排序机制,即使在加入的 table.
中没有使用测量
然后,下一个外部查询只抓取 RowNum = 1 的行。
我有一个 table,其中包含机器销售的制造商、型号、序列号和发票日期,我想将其与包含制造商、序列号的 table 配对,记录的使用情况、使用单位和记录日期 - 除了 Usage/Record Table 是 HUUUUUUGE 并且可能没有每台机器的记录。
我试过编写一个 OUTER JOIN,但是 Usage/Record 中的数据太多 table,无法有效地运行。我试着写了一个 CROSS APPLY,但我一定是搞砸了,因为那似乎也不是很有效。
文件示例:
我的基本查询:
Inv. Date Mk Model Serial
2019-03-29 AA 420D 0FDP09999
2019-03-21 AA A19B-SSL 0DX240481
Usage/Records Table:
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
...仅返回发票日期之前的最新条目的使用情况、单位和记录日期。
有什么建议吗?
您可以尝试左连接和 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])
上的索引 table。或者,如果连续剧或多或少 "unique" 也超过不同品牌,则可以尝试切换 [Mk]
和 [Serial]
的位置。
为了解决这个问题,我最终在最初的基本查询之外创建了额外的查询。
在第一个外部查询中,我这样做了("Invoice Number" 是我调用的一个附加字段,以确保唯一的行编号,以防机器被出售一次,买回,然后再次出售时间段):
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]
这确保 table 中的每个条目都有排序机制,即使在加入的 table.
中没有使用测量然后,下一个外部查询只抓取 RowNum = 1 的行。