【发布时间】:2023-03-10 20:00:01
【问题描述】:
我一直在努力改善现有 Oracle 数据库驱动应用程序的查询时间,该应用程序运行缓慢。该应用程序执行几个大型查询,例如下面的查询,可能需要一个多小时才能运行。在下面的查询中将DISTINCT 替换为GROUP BY 子句将执行时间从100 分钟缩短到10 秒。我的理解是SELECT DISTINCT 和GROUP BY 的运作方式几乎相同。为什么执行时间之间存在如此巨大的差异?查询在后端执行的方式有什么区别?有没有SELECT DISTINCT跑得更快的情况?
注意:在以下查询中,WHERE TASK_INVENTORY_STEP.STEP_TYPE = 'TYPE A' 仅代表可以过滤结果的多种方式之一。提供此示例是为了说明连接所有表的原因,这些表没有包含在 SELECT 中的列,并且会产生大约十分之一的可用数据
使用DISTINCT的SQL:
SELECT DISTINCT
ITEMS.ITEM_ID,
ITEMS.ITEM_CODE,
ITEMS.ITEMTYPE,
ITEM_TRANSACTIONS.STATUS,
(SELECT COUNT(PKID)
FROM ITEM_PARENTS
WHERE PARENT_ITEM_ID = ITEMS.ITEM_ID
) AS CHILD_COUNT
FROM
ITEMS
INNER JOIN ITEM_TRANSACTIONS
ON ITEMS.ITEM_ID = ITEM_TRANSACTIONS.ITEM_ID
AND ITEM_TRANSACTIONS.FLAG = 1
LEFT OUTER JOIN ITEM_METADATA
ON ITEMS.ITEM_ID = ITEM_METADATA.ITEM_ID
LEFT OUTER JOIN JOB_INVENTORY
ON ITEMS.ITEM_ID = JOB_INVENTORY.ITEM_ID
LEFT OUTER JOIN JOB_TASK_INVENTORY
ON JOB_INVENTORY.JOB_ITEM_ID = JOB_TASK_INVENTORY.JOB_ITEM_ID
LEFT OUTER JOIN JOB_TASKS
ON JOB_TASK_INVENTORY.TASKID = JOB_TASKS.TASKID
LEFT OUTER JOIN JOBS
ON JOB_TASKS.JOB_ID = JOBS.JOB_ID
LEFT OUTER JOIN TASK_INVENTORY_STEP
ON JOB_INVENTORY.JOB_ITEM_ID = TASK_INVENTORY_STEP.JOB_ITEM_ID
LEFT OUTER JOIN TASK_STEP_INFORMATION
ON TASK_INVENTORY_STEP.JOB_ITEM_ID = TASK_STEP_INFORMATION.JOB_ITEM_ID
WHERE
TASK_INVENTORY_STEP.STEP_TYPE = 'TYPE A'
ORDER BY
ITEMS.ITEM_CODE
使用GROUP BY的SQL:
SELECT
ITEMS.ITEM_ID,
ITEMS.ITEM_CODE,
ITEMS.ITEMTYPE,
ITEM_TRANSACTIONS.STATUS,
(SELECT COUNT(PKID)
FROM ITEM_PARENTS
WHERE PARENT_ITEM_ID = ITEMS.ITEM_ID
) AS CHILD_COUNT
FROM
ITEMS
INNER JOIN ITEM_TRANSACTIONS
ON ITEMS.ITEM_ID = ITEM_TRANSACTIONS.ITEM_ID
AND ITEM_TRANSACTIONS.FLAG = 1
LEFT OUTER JOIN ITEM_METADATA
ON ITEMS.ITEM_ID = ITEM_METADATA.ITEM_ID
LEFT OUTER JOIN JOB_INVENTORY
ON ITEMS.ITEM_ID = JOB_INVENTORY.ITEM_ID
LEFT OUTER JOIN JOB_TASK_INVENTORY
ON JOB_INVENTORY.JOB_ITEM_ID = JOB_TASK_INVENTORY.JOB_ITEM_ID
LEFT OUTER JOIN JOB_TASKS
ON JOB_TASK_INVENTORY.TASKID = JOB_TASKS.TASKID
LEFT OUTER JOIN JOBS
ON JOB_TASKS.JOB_ID = JOBS.JOB_ID
LEFT OUTER JOIN TASK_INVENTORY_STEP
ON JOB_INVENTORY.JOB_ITEM_ID = TASK_INVENTORY_STEP.JOB_ITEM_ID
LEFT OUTER JOIN TASK_STEP_INFORMATION
ON TASK_INVENTORY_STEP.JOB_ITEM_ID = TASK_STEP_INFORMATION.JOB_ITEM_ID
WHERE
TASK_INVENTORY_STEP.STEP_TYPE = 'TYPE A'
GROUP BY
ITEMS.ITEM_ID,
ITEMS.ITEM_CODE,
ITEMS.ITEMTYPE,
ITEM_TRANSACTIONS.STATUS
ORDER BY
ITEMS.ITEM_CODE
这里是使用DISTINCT的查询的Oracle查询计划:
这里是使用GROUP BY的查询的Oracle查询计划:
【问题讨论】:
-
用
group by显示查询。 -
我没有你的问题的答案,但我希望看到这两个查询、它们的解释计划和逻辑 GET 的数量可能有助于理解(FWIW 我本来希望 DISTINCT 有一个性能优势,如果有的话)。
-
在 SQL Server 中,您可以获得查询执行计划。您可以在 Oracle 中获得类似的东西吗?这会告诉你区别在哪里。
-
顺便说一句:当您只想要末尾带有“A 型”的记录时,为什么要加入大长链 LEFT?
-
两件事; 1)将您的 GROUP BY 查询放入您的问题中,2)对每个查询运行 EXPLAIN PLAN,并将输出添加到问题中。
标签: sql performance oracle group-by distinct