我有一个相当复杂的SQL查询,涉及从大量联接中返回大约20列,这些联接用于在UI中填充结果网格。它还使用几个CTE来预过滤结果。我在下面包括了近似的查询(我已经注释掉了固定性能的行)
随着数据库中数据量的增加,查询性能大打折扣,主表“合同”中只有大约2500行。
通过实验,我发现只需删除订单,最后进行偏移获取,性能就从大约30秒缩短到了1秒!
order by 1 OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
这对我来说毫无意义。最后一行应该相当便宜,即使OFFSET为零也可以免费使用,那为什么还要增加29秒的查询时间呢?
为了对SQL保持相同的功能,我对其进行了修改,以便首先选择#TEMP,然后在temp表上执行上述order-offset-fetch,然后删除temp表。这将在大约2-3秒内完成。
我的“优化”感觉很不对劲,肯定有更明智的方法来达到相同的速度吗?
我还没有针对较大的数据集进行过广泛的测试,从本质上讲,这是一种快速恢复性能的快速解决方案。我怀疑随着数据大小的增长它是否会有效。
除主键上的聚簇索引外,表上没有索引。 Query Execution计划似乎没有显示任何主要瓶颈,但我不是解释它的专家。
WITH tableOfAllContractIdsThatMatchRequiredStatus(contractId)
AS (
SELECT DISTINCT c.id
FROM contract c
INNER JOIN site s ON s.ContractId = c.id
INNER JOIN SiteSupply ss ON ss.SiteId = s.id AND ss.status != 'Draft'
WHERE
ISNULL(s.Deleted, '0') = 0
AND ss.status in ('saved')
)
,tableOfAllStatusesForAContract(contractId, status)
AS (
SELECT DISTINCT c.id, ss.status
FROM contract c
INNER JOIN site s ON s.ContractId = c.id
INNER JOIN SiteSupply ss ON ss.SiteId = s.id AND ss.status != 'Draft'
WHERE ss.SupplyType IN ('Electricity') AND ISNULL(s.Deleted, '0') = 0
)
SELECT
[Contract].[Id]
,[Contract].[IsMultiSite]
,statuses.StatusesAsCsv
... lots more columns
,[WaterSupply].[Status] AS ws
--INTO #temp
FROM
(
SELECT
tableOfAllStatusesForAContract.contractId,
string_agg(status, ', ') AS StatusesAsCsv
FROM
tableOfAllStatusesForAContract
GROUP BY
tableOfAllStatusesForAContract.contractId
) statuses
JOIN contract ON Contract.id = statuses.contractId
JOIN tableOfAllContractIdsThatMatchRequiredStatus ON tableOfAllContractIdsThatMatchRequiredStatus.contractId = Contract.id
JOIN Site ON contract.Id = site.contractId and site.isprimarySite = 1 AND ISNULL(Site.Deleted,0) = 0
... several more joins
JOIN [User] ON [Contract].ownerUserId = [User].Id
WHERE isnull(Deleted, 0) = 0
AND
(
[Contract].[Id] = '12659'
OR [Site].[Id] = '12659'
... often more search term type predicates here
)
--select * from #temp
order by 1
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
--drop table #temp
答案 0 :(得分:0)
我没有答案,因此我将尝试自己解释一下,因为我对SQL的工作原理认识不足,并且在上面的注释中有Jeroen的一些提示。这可能不正确,但是从我发现的情况来看可能是正确的,而且我确实知道如何解决眼前的问题,从而可以帮助他人。
我将以类推的方式进行解释,因为我认为这可能正在发生:
想象一下,您是一家餐馆的厨师,而您必须准备大量的饭菜(rows in results
。您知道屋前告诉您的内容(TOP 10 or FETCH 10
将会有很多。
您花时间确定所需的多种原料(table joins
)和所需的设备,并且在收到第一笔订单时,请确保您将真正提高效率。切碎第一个订单所需的更多物品,将其放入小碗中,以备后继使用。第一份订单要花很长时间(30 secs
),因为您要提前计划,并希望后续的菜肴尽快出炉。
但是,当您坐在厨房里等待下一个订单时,..请不要到达。就是这样,只需一个订单。好吧,那是浪费时间!如果您只是想拿出一盘菜,可以做得更快(1sec
),但是您正在为不需要的东西做计划。
第二天晚上,您放弃了先前的策略,一次只做每个盘子。但是这一次有100个客户。您无法一次快速地交付它们。如果您像前一天晚上那样提前计划,则交付所有订单的时间将大大缩短。 (我尚未检验这个假设,但我希望它可能会发生)。
对于我的查询,我不知道会有1个结果还是100个结果,尽管我可能可以根据用户输入的搜索条件预先进行一些分析,但我可能必须调整UI以适应给我更多信息,以便我可以更好地进行预测,这意味着我可以为SQL选择合适的策略以预先使用。照原样,我已经针对少量结果进行了优化,这些结果目前可以正常工作-但我需要做一些更广泛的测试,以了解随着数据集的增长性能如何受到影响。
"If you want a answer to something, post something that's wrong on the internet and someone will be sure to correct you"