1

我编写这个查询是为了将产品预测数据与 Oracle 星型模式数据库中的历史出货数据联系起来,而优化器的运行方式与我预期的不同,所以我有点好奇发生了什么。

本质上,我有一堆维度表,它们对于预测和销售事实表都是一致的,但是事实表在不同的级别聚合,所以我将它们设置为两个子查询并将它们汇总起来,这样我就可以将它们捆绑起来一起(下面的查询示例。)在这种情况下,我想要所有的预测数据,但只有匹配的销售数据。

奇怪的是,如果我自己使用任何一个子查询,它们似乎都表现得像我预期的那样,并且每个都在不到一秒的时间内返回(使用相同的过滤器——我通过删除一个或另一个子查询进行测试并更改别名)。

这是查询结构的一个示例——我尽可能地保持它的通用性,因此更改它可能会出现一些拼写错误:

SELECT
     TIME_DIMENSION.GREGORIAN_DATE,
     LOCATION_DIMENSION.LOCATION_CODE,
     DESTINATION_DIMENSION.REGION,
     PRODUCT_DIMENSION.PRODUCT_CODE,
     SUM(NVL(FIRST_SUBQUERY.VALUE,0)) VALUE1,
     SUM(NVL(SECOND_SUBQUERY.VALUE,0)) VALUE2
FROM
     TIME_DIMENSION,
     LOCATION_DMENSION SOURCE_DIMENSION,
     LOCATION_DIMENSION DESTINATION_DIMENSION,
     PRODUCT_DIMENSION,
     (SELECT
        FORECAST_FACT.TIME_KEY,
        FORECAST_FACT.SOURCE_KEY,
        FORECAST_FACT.DESTINATION_KEY,
        FORECAST_FACT.PRODUCT_KEY,
        SUM(FORECAST_FACT.VALUE) AS VALUE,
     FROM FORECAST_FACT
     WHERE [FORECAST_FACT FILTERS HERE]
     GROUP BY
        FORECAST_FACT.TIME_KEY,
        FORECAST_FACT.SOURCE_KEY,
        FORECAST_FACT.DESTINATION_KEY) FIRST_SUBQUERY
LEFT JOIN
    (SELECT
        --This is just as an example offset
        (LAST_YEAR_FACT.TIME_KEY + 52) TIME_KEY,        
        LAST_YEAR_FACT.SOURCE_KEY,
        LAST_YEAR_FACT.DESTINATION_KEY,
        FORECAST_FACT.PRODUCT_KEY,
        SUM(LAST_YEAR_FACT.VALUE) AS VALUE,
     FROM LAST_YEAR_FACT
     WHERE [LAST_YEAR_FACT FILTERS HERE]
     GROUP BY
        LAST_YEAR_FACT.TIME_KEY,
        LAST_YEAR_FACT.SOURCE_KEY,
        LAST_YEAR_FACT.DESTINATION_KEY) SECOND_SUBQUERY
ON
    FORECAST_FACT.TIME_KEY = LAST_YEAR_FACT.TIME_KEY
    AND FORECAST_FACT.SOURCE_KEY = LAST_YEAR_FACT.SOURCE_KEY
    AND FORECAST_FACT.DESTINATION_KEY = LAST_YEAR_FACT.DESTINATION_KEY
    --I also tried to tie the last_year subquery to the dimension tables here
WHERE
    FORECAST_FACT.TIME_KEY = TIME_DIMENSION.TIME_KEY
    AND FORECAST_FACT.SOURCE_KEY = SOURCE_DIMENSION.LOCATION_KEY
    AND FORECAST_FACT.DESTINATION_KEY = DESTINATION_DIMENSION.LOCATION_KEY
    AND FORECAST_FACT.PRODUCT_KEY  = PRODUCT_DIMENSION.PRODUCT_KEY
    --I also tried, separately, to tie the last_year subquery to the dimension tables here
    AND TIME_DIMENSION.WEEK = 'VALUE'
    AND SOURCE_DIMENSION.SOURCE_CODE = 'VALUE'
    AND DESTINATION_DIMENSION.REGION IN ('VALUE', 'VALUE')
    AND PRODUCT_DIMENSION.CLASS_CODE = 'VALUE'
GROUP BY
    TIME_DIMENSION.GREGORIAN_DATE,
    SOURCE_DIMENSION.LOCATION_CODE,
    DESTINATION_DIMENSION.REGION,
    PRODUCT_DIMENSION.PRODUCT_CODE

本质上,当我独立运行任一子查询时,它将利用索引并仅搜索特定分区的特定范围,而使用左连接时,它总是对其中一个事实表进行全表扫描。似乎正在发生的事情是 Oracle 仅将维度表过滤器应用于第一个子查询——因此要进行左连接,它首先需要扫描整个销售表——即使我明确地绑定并过滤了两次值,而不是依赖隐式过滤...我试过了。我想错了吗?对我来说,优化器应该使用两个事实表上的索引来过滤每个 WHERE 子句中的值,然后左连接结果子集。

我意识到我可以简单地将过滤器添加到每个子查询中,或者将其设置为两个独立查询的联合,但我很好奇优化引擎到底发生了什么——我可以发布执行计划,如果有帮助的话。

谢谢!

4

1 回答 1

0

确保所有表格都经过分析。再来一遍。优化器使用这些值来计算它的执行计划。如果 Oracle 确实选择了错误的计划,您的解决方法是使用提示 /*+ ... */ 强制优化器,指定索引的使用、连接顺序等。

于 2013-07-29T20:46:43.733 回答