我有一个非常简单的查询,该查询需要长时间返回前20行。
SELECT o.OrderId,
p.PaymentDate
FROM dbo.Orders o -- 6 million records
LEFT JOIN dbo.Payments p ON p.OrderId = o.OrderId -- 3.5 million records
WHERE o.IsDeleted = 0 -- There is an index on this column.
ORDER BY p.PaymentDate DESC -- There is an index on this column and on OrderId
OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY
执行计划显示订单和付款表上的索引扫描,从订单中读取了600万行,从付款表中读取了300万行。
返回20行大约需要4-5秒。
如何使此查询返回结果更快?
您正在排序一个巨大的数据集,只是为了检索20行
如果这是一个典型的订单系统,那么ISDEATED = 0可能没有太大帮助,因为将删除订单的百分比?0.1%?排除它们对您要排序的订单数量
几乎没有影响我也将付款状态标准放在那里,在那里也有稍微缩小记录的计数,以便对较小的集合进行分类。目前,您想要的逻辑是您想要20个记录,但是您不需要对600万张记录进行排序即可获得20个记录。将其剪切到20个记录。显然,这是一个忙碌的订购系统,每天至少要提交20个订单,因此您可能会发现只有一天以来仅使用Paymant Date选择记录,请从一天开始获得20个订单,但请选择很多天以给您20,甚至可能实施一些逻辑,如果您没有获得20次首次回合,那么您的前端应用程序会增加天数。您可以在前端缓存此回忆值,并随着天数的流逝而再次减少它,因此它成为自动派生的图
我认为您的另一个问题是您已经成为了左JON的,但是我看不到这样做的感觉 - 您是最近付费的订单,对吗?没有未付订单的付款记录?不管有600万订单付款的原因是什么,您似乎对没有付款记录的订单不感兴趣,所以我看不到让它成为左JON的感觉您绝对不想要的250万张唱片。使其成为内在的联接
您在付款日期之前进行排序 - 因此,您似乎需要匹配。因此,inner join
就足够了。
此外,OrderId
在付款表中。因此,您可以尝试此版本:
SELECT p.OrderId, p.PaymentDate
FROM dbo.Payments p
WHERE EXISTS (SELECT 1
FROM dbo.Orders o
WHERE p.OrderId = o.OrderId AND
o.IsDeleted = 0
)
ORDER BY p.PaymentDate DESC
OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY;
然后,对于此查询,您需要一个索引:
-
Payments(PaymentDate DESC, OrderId)
-
Orders(OrderId, IsDeleted)
。