使用交叉应用子查询优化 sql 查询的问题
Posted
技术标签:
【中文标题】使用交叉应用子查询优化 sql 查询的问题【英文标题】:Problem optimizing sql query with cross apply sub query 【发布时间】:2021-03-31 05:14:10 【问题描述】:所以我有三张桌子:
MakerParts,保存车辆零件的主要信息:
Id | MakerId | PartNumber | Description |
---|---|---|---|
1 | 1 | ABC1234 | Tire |
2 | 1 | XYZ1234 | Door |
MakerPrices
,保存零件的价格历史变化(参考MakerPartNumberId
上的MakerParts.Id
,以及MakerPriceUpdates
上UpdateId
上的表格):
Id | MakerPartNumberId | UpdateId | Price |
---|---|---|---|
1 | 1 | 1 | 9.83 |
2 | 1 | 2 | 11.23 |
MakerPriceUpdates
,保存价格更新的日期。此更新基本上是上传到我们系统的 CSV 文件。一个文件,此表一行,表上多个价格变化MakerPrices
。
Id | Date | FileName |
---|---|---|
1 | 2019-01-09 00:00:00.000 | temp.csv |
2 | 2019-01-11 00:00:00.000 | temp2.csv |
这意味着一个零件 (MakerParts) 可能有多个价格 (MakerPrices)。价格变化的日期在 MakerPricesUpdates 表中。
我想选择所有最近价格为零的 MakerParts,按 MakerParts 表上的 MakerId 进行过滤。
我尝试过的:
select mp.* from MakerParts mp cross apply
(select top 1 Price from MakerPrices inner join
MakerPricesUpdates on MakerPricesUpdates.Id = MakerPrices.UpdateId where
MakerPrices.MakerPartNumberId = mp.Id order by Date desc) as p
where mp.MakerId = 1 and p.Price = 0
但这太慢了(我们在 MakerPrices 表上有大约 1 亿行)。我很难优化这个查询。 (结果是MakerId 1只有两行,运行了2分钟)。我也试过了:
select * from (
select
mp.*,
(select top 1 Price from MakerPrices inner join
MakerPricesUpdates on MakerPricesUpdates.Id = MakerPrices.UpdateId
where MakerPrices.MakerPartNumberId = mp.Id order by Date desc) as Price
from MakerParts mp) as temp
where temp.Price = 0 and MakerId = 1
同样的结果,同样的时间。我的查询计划(针对第一个查询)(Management Studio 没有建议新索引):
【问题讨论】:
为什么它不应该是像下面这样的内部连接?这不会给你想要的结果吗?请检查。 select mp.* from MakerParts mp join (select top 1 Price, MakerPartNumberId from MakerPrices inner join MakerPricesUpdates on MakerPricesUpdates.Id = MakerPrices.UpdateId where MakerPrices.MakerPartNumberId = mp.Id order by Date desc) as p where mp.id = p. MakerPartNumberId 和 mp.MakerId = 1 和 p.Price = 0 这给了我Incorrect syntax near the keyword 'where'
。我正在使用 SQL Azure V12。
将第一个 join
更改为 cross apply
有效,但速度很慢。
请参阅小提琴网址中的查询以供参考。 dbfiddle.uk/…谢谢
@praveen 谢谢。我得到零行作为响应。我相信内部的select top 1 * from MakerPricesUpdates order by Date desc
总是会返回相同的更新Id。这样,只会检查最近更新的零件价格,并且在此更新中更新了一些 MakerPrice,但没有价格 = 0
【参考方案1】:
我认为你可以避免加入MakerPriceUpdates
和makerprices
,因为最高
UpdateId
你可以找到最新的价格更新。这将为您节省一些时间。
select mp.* from MakerParts mp cross apply
(select top 1 Price from MakerPrices where
MakerPrices.MakerPartNumberId = mp.Id order by MakerPrices.UpdateId desc) as p
where mp.MakerId = 1 and p.Price = 0
您可以通过使用 cte 和 row_number() 避免排序和排序来进一步减少一些时间,如下所示:
;with LatestMakerPrices as
(
select *,row_number()over(partition by MakerPartNumberId order by updateid desc)rn from MakerPrices
)
select mp.* from MakerParts mp cross apply
(select price from LatestMakerPrices lmp where lmp.MakerPartNumberId=mp.Id) as p
where mp.MakerId = 1 and p.Price = 0
有问题的查询与我的答案之间的执行计划差异:
【讨论】:
很好,第二个查询立即运行!不幸的是,按日期排序是强制性的,因为用户可以上传“旧”CSV(他们实际上是在 UI 中选择日期)。无论如何使用您的第二个查询 ordering desc by date? 请让我先试试。 当然!我需要睡一会儿,我的头快要死了。我明天再来检查;没必要着急。非常感谢。 请根据巴基斯坦时间明天下午 3:00 与我讨论,我将根据您的需要编写算法,这将为您提供更好的性能@Guilherme【参考方案2】:尝试:
WITH tab AS (
SELECT *, NULL as Price FROM MakerParts
WHERE not exists (
SELECT Id
FROM MakerPrices
WHERE MakerPrices.MakerPartNumberId = MakerParts.Id
)
)
SELECT * from tab WHERE MakerId = 2
UNION ALL
SELECT a.* , Price
FROM [dbo].[MakerParts] a
LEFT JOIN [dbo].[MakerPrices] b
ON b.MakerPartNumberId = a.Id
WHERE MakerId = 2 AND Price = 0
【讨论】:
谢谢,但这超出了预期的两行。在额外的价格中,最近的价格> 0。【参考方案3】:试试你的查询:
select mp.* from MakerParts mp cross apply
(select top 1 Price from MakerPrices inner join
MakerPricesUpdates on MakerPricesUpdates.Id = MakerPrices.UpdateId where
MakerPrices.MakerPartNumberId = mp.Id order by Date desc) as p
where mp.MakerId = 1 and p.Price = 0
创建以下索引后:
CREATE NONCLUSTERED INDEX [NCIdx_MakerPrices_MakerPartNumberId_UpdateId] ON [dbo].[MakerPrices]
(
[MakerPartNumberId] ASC,
[UpdateId] ASC
)
INCLUDE([Price])
并制作ID
列的MakerPricesUpdates
表主键。
【讨论】:
谢谢!不幸的是,现在我得到了价格 = 0 的“任何”部分。结果部分的最新价格 > 0,之所以选择它们是因为过去其中一个价格是零。还有什么想法吗? 请分享一些示例数据以便更好地理解。 制作 MakerPricesUpdates 表的 ID 列主键(如果没有)并在问题中创建索引并尝试执行您的查询。以上是关于使用交叉应用子查询优化 sql 查询的问题的主要内容,如果未能解决你的问题,请参考以下文章