长选需要 55 秒才能显示结果,更好的咨询方式?
Posted
技术标签:
【中文标题】长选需要 55 秒才能显示结果,更好的咨询方式?【英文标题】:Long select is taking 55 secs to display the result, better way to consult? 【发布时间】:2018-12-11 20:12:40 【问题描述】:简介
大家好,我正在尝试进行大选择,但我遇到了一个主要问题,此查询需要 55 多秒才能显示 13,000 行,因为有 4 个子查询(搜索同一个表)他们是:
-
父链接如此自动
父链接 SO LINE AUT
PLSO AUT 创建日期
请确认发货日期
这4列只有在DEM_TYPE为'WO'时才会得到数据,这就是我在每个子查询中放入CASE WHEN的原因>.
如果 DEM_TYPE 不是 'WO' 那 4 列将为 NULL
我只需要在子查询中找到它的第一行,这就是我使用 TOP 1 的原因。
接下来我将向您展示查询和表格的结果
CREATE UNIQUE INDEX IDX_TMP
ON ENT_DEMAND_SUPPLY(ROWID);
SELECT ONE.ROWID, ONE.PLANNER, ONE.BUYER, ONE.DEM_TYPE, ONE.DEM_SOURCE, ONE.DEM_SOURCE_LINE, ONE.DEM_PART_ID, ONE.[PART ID DESCRIPTION], ONE.DEM_QTY, ONE.ACUM_ASSIGN_QTY, ONE.ASSIGNED_QTY, ONE.SUPPLY_TYPE, ONE.SUPPLY_SOURCE, ONE.SUPPLY_SOURCE_LINE, ONE.SUPPLY_QTY, ONE.REST_QTY, ONE.SUPPLIER, ONE.[PO STATUS], ONE.[WO STATUS], ONE.[SO CREATED DATE], ONE.[WO CREATED DATE], ONE.[SO PROMISE SHIP DATE PER LINE], ONE.[WO RELEASE DATE], ONE.[PO PLACE DATE], ONE.[SITE ARRIVAL], ONE.[UPDATE SHIP DATE], ONE.[INITIAL SHIP DATE], ONE.[LEAD TIME PROVIDE] AS 'LEAD TIME PROVIDE BY SCHEDULER', ONE.[LEAD TIME REQUIRED TO SUPPLIER], ONE.[LEAD TIME STANDARD], ONE.[QUALITY WAREHOUSE], ONE.COMMENTS, ONE.[SO LINK ERP], ONE.[SO LINE LINK ERP], ONE.[PARENT LINK SO ERP], ONE.[PARENT LINK SO LINE ERP], ONE.PLSO_ERP_CREATE_DATE, ONE.PLSO_ERP_SHIPPED_DATE
,CASE WHEN ONE.DEM_TYPE = 'WO' THEN (SELECT TOP 1 DEM_SOURCE FROM ENT_DEMAND_SUPPLY WHERE SUPPLY_TYPE = 'WO' AND SUPPLY_SOURCE = ONE.DEM_SOURCE AND SUPPLY_SOURCE_LINE = ONE.DEM_SOURCE_LINE ORDER BY DEM_PART_ID, DEM_DATE) ELSE NULL END AS 'PARENT LINK SO AUT'
,CASE WHEN ONE.DEM_TYPE = 'WO' THEN (SELECT TOP 1 DEM_SOURCE_LINE FROM ENT_DEMAND_SUPPLY WHERE SUPPLY_TYPE = 'WO' AND SUPPLY_SOURCE = ONE.DEM_SOURCE AND SUPPLY_SOURCE_LINE = ONE.DEM_SOURCE_LINE ORDER BY DEM_PART_ID, DEM_DATE) ELSE NULL END AS 'PARENT LINK SO LINE AUT'
,CASE WHEN ONE.DEM_TYPE = 'WO' THEN (SELECT TOP 1 [PLSO_ERP_CREATE_DATE] FROM ENT_DEMAND_SUPPLY WHERE SUPPLY_TYPE = 'WO' AND SUPPLY_SOURCE = ONE.DEM_SOURCE AND SUPPLY_SOURCE_LINE = ONE.DEM_SOURCE_LINE ORDER BY DEM_PART_ID, DEM_DATE) ELSE NULL END AS 'PLSO AUT CREATED DATE'
,CASE WHEN ONE.DEM_TYPE = 'WO' THEN (SELECT TOP 1 [PLSO_ERP_SHIPPED_DATE] FROM ENT_DEMAND_SUPPLY WHERE SUPPLY_TYPE = 'WO' AND SUPPLY_SOURCE = ONE.DEM_SOURCE AND SUPPLY_SOURCE_LINE = ONE.DEM_SOURCE_LINE ORDER BY DEM_PART_ID, DEM_DATE) ELSE NULL END AS 'PLSO AUT SHIPPED DATE'
FROM ENT_DEMAND_SUPPLY ONE
ORDER BY ONE.DEM_PART_ID, ONE.DEM_DATE
DROP INDEX ENT_DEMAND_SUPPLY.IDX_TMP
Table result part 1 Table result part 2
如您所见,在第 1 行。 8 DEM_TYPE 是一个“WO”,其 DEM_SOURCE 值为 12900,DEM_SOURCE_LINE 值为 1(表格结果第 1 部分) 所以在这种情况下,将运行 4 个子查询(表结果第 2 部分)
*在图片中没有。 2 , PLSO AUT CREATED DATE 和 PLSO AUT SHIPPED DATE 为 NULL,这是有效的,因为它可以存在也可以不存在这些记录
子查询逻辑
关于这个东西的逻辑是:我必须在整个表中找到 SUPPLY_SOURCE 中的 DEM_SOURCE 和 SUPPLY_SOURCE_LINE 中的 DEM_SOURCE_LINE,例如我们返回第 8 行。
如果我们取行号。 8 我们有这些值... DEM_TYPE = 'WO', DEM_SOURCE: 12900 和 DEM_SOURCE_LINE = 1,我可以让子查询准备好搜索并获取该行的 4 个额外列,如下所示:
(SELECT TOP 1 DEM_SOURCE FROM ENT_DEMAND_SUPPLY WHERE SUPPLY_TYPE = 'WO' AND SUPPLY_SOURCE = '12900' AND SUPPLY_SOURCE_LINE = '1')
Sub-query result
如果您检查图片编号。 2,这 4 个值将在最后 4 列中,并带有我们开始讨论的 4 个名称......当 DEM_TYPE 为“WO”时,我必须为每一行执行这些过程,有人知道我可以如何改进它吗?我尝试使用索引,它有帮助,但速度不够快。 非常感谢您花时间阅读这篇文章,如果您有任何问题或建议,请告诉我!
【问题讨论】:
听起来你想加入。您是否尝试过创建一个临时表或仅包含您想要过滤的结果的 CTE,然后加入该表(因为您提到您正在多次查看同一个表)? 我担心您的所有子查询都使用SELECT TOP 1...
而没有ORDER BY
@TTeeple 是的,我试过了,但我无法得到答案,当我尝试使用 LEFT JOIN 时,我得到的行数比原始表多,这是因为 LEFT JOIN 得到了所有行在 MATCH 中,我只想要第一个,而 CTE 在这种情况下我不知道如何处理它
如果左连接增加了行数,则您没有使用唯一键来连接表。这很糟糕,因为这意味着如果您在没有 ORDER BY 的情况下使用 TOP 1,您将无法确定会选择什么值。如果键包含多个相同的值,请使用 DISTINCT 或 GROUP BY 来防止行增加
为什么要在主表上创建唯一索引,只在查询后删除?您应该创建一次并将其留在那里或根本不使用它。
【参考方案1】:
在我看来,在一个查询中加载所有数据是一种不好的做法。如果是为了延迟加载在某处缓存数据,那可能是可以接受的,但如果您尝试为用户加载数据,那么分页会是更好的选择。
希望您为SUPPLY_TYPE
、SUPPLY_SOURCE
、SUPPLY_SOURCE_LINE
创建索引,因为它可以缩短查询时间。
对于您的问题,您可以使用OUTER APPLY
- Sql server cross apply and outer apply
我未经测试的快速回复将是(仍有空间需要修改):
SELECT
ONE.ROWID, ONE.PLANNER, ONE.BUYER, ONE.DEM_TYPE, ONE.DEM_SOURCE, ONE.DEM_SOURCE_LINE, ONE.DEM_PART_ID, ONE.[PART ID DESCRIPTION], ONE.DEM_QTY, ONE.ACUM_ASSIGN_QTY, ONE.ASSIGNED_QTY, ONE.SUPPLY_TYPE, ONE.SUPPLY_SOURCE, ONE.SUPPLY_SOURCE_LINE, ONE.SUPPLY_QTY, ONE.REST_QTY, ONE.SUPPLIER, ONE.[PO STATUS], ONE.[WO STATUS], ONE.[SO CREATED DATE], ONE.[WO CREATED DATE], ONE.[SO PROMISE SHIP DATE PER LINE], ONE.[WO RELEASE DATE], ONE.[PO PLACE DATE], ONE.[SITE ARRIVAL], ONE.[UPDATE SHIP DATE], ONE.[INITIAL SHIP DATE], ONE.[LEAD TIME PROVIDE] AS 'LEAD TIME PROVIDE BY SCHEDULER', ONE.[LEAD TIME REQUIRED TO SUPPLIER], ONE.[LEAD TIME STANDARD], ONE.[QUALITY WAREHOUSE], ONE.COMMENTS, ONE.[SO LINK ERP], ONE.[SO LINE LINK ERP], ONE.[PARENT LINK SO ERP], ONE.[PARENT LINK SO LINE ERP], ONE.PLSO_ERP_CREATE_DATE, ONE.PLSO_ERP_SHIPPED_DATE
,CASE WHEN ONE.DEM_TYPE = 'WO' THEN [Table2].[DEM_SOURCE] ELSE NULL END AS 'PARENT LINK SO AUT'
,CASE WHEN ONE.DEM_TYPE = 'WO' THEN [Table2].[DEM_SOURCE_LINE] ELSE NULL END AS 'PARENT LINK SO LINE AUT'
,CASE WHEN ONE.DEM_TYPE = 'WO' THEN [Table2].[PLSO_ERP_CREATE_DATE] ELSE NULL END AS 'PLSO AUT CREATED DATE'
,CASE WHEN ONE.DEM_TYPE = 'WO' THEN [Table2].[PLSO_ERP_SHIPPED_DATE] ELSE NULL END AS 'PLSO AUT SHIPPED DATE'
FROM
ENT_DEMAN_SUPPLY ONE
OUTER APPLY(
SELECT TOP 1
DEM_SOURCE
,DEM_SOURCE_LINE
,PLSO_ERP_CREATE_DATE
,PLSO_ERP_SHIPPED_DATE
FROM
ENT_DEMAND_SUPPLY [TWO]
WHERE --These columns should be indexed
[TWO].SUPPLY_TYPE = 'WO'
AND [TWO].SUPPLY_SOURCE = ONE.DEM_SOURCE
AND [TWO].SUPPLY_SOURCE_LINE = ONE.DEM_SOURCE_LINE
) [Table2]
ORDER BY ONE.DEM_PART_ID, ONE.DEM_DATE
【讨论】:
您好,非常感谢您的回答,但不幸的是它没有用,我得到了 NULL 的最后 4 列,我将检查OUTER APPLY
感谢您的提示!
在我编辑我的答案之前有[TWO].[ROWID] = [ONE].[ROWID]
,尝试删除它
等等!我刚刚删除了 [Table2] 中的第一个 WHERE 条件,即行 ID 等于另一个行 ID,它可以工作!现在只需要 23 秒,而且还没有索引!我会让你知道如何结束谢谢
完美运行! 1 秒完成选择非常感谢。以上是关于长选需要 55 秒才能显示结果,更好的咨询方式?的主要内容,如果未能解决你的问题,请参考以下文章
MySQL-Simple Query 需要 11 秒才能返回结果