Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 优化Oracle查询_Sql_Oracle_Optimization - Fatal编程技术网

Sql 优化Oracle查询

Sql 优化Oracle查询,sql,oracle,optimization,Sql,Oracle,Optimization,在此查询上运行explain plan,我将获得完整的表访问权限 使用的两个表格是: user_role: 803507 rows cmp_role: 27 rows 查询: SELECT r.user_id, r.role_id, r.participant_code, MAX(status_id) FROM user_role r, cmp_role c WHERE r.role_id = c.role_id AND r

在此查询上运行explain plan,我将获得完整的表访问权限

使用的两个表格是:

user_role:   803507 rows
cmp_role:    27 rows
查询:

SELECT 
   r.user_id, r.role_id, r.participant_code, MAX(status_id) 
  FROM 
    user_role r, 
    cmp_role c 
  WHERE 
    r.role_id = c.role_id 
    AND r.participant_code IS NOT NULL 
    AND c.group_id = 3 
    GROUP BY 
    r.user_id, r.role_id, r.participant_code 
    HAVING MAX(status_id) IN (SELECT b.status_id FROM USER_ROLE b 
                              WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )  
    AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date 
                                    )) 
                             )
如何更好地编写此查询,以便在适当的时间内返回结果。以下是索引:

idx 1 = role_id
idx 2 = last_updt_user_id
idx 3 = actv_id, participant_code, effective_from_Date, effective_to_date
idx 4 = user_id, role_id, effective_from_Date, effective_to_date
idx 5 = participant_code, user_id, roke_id, actv_cd
解释计划:

Q_PLAN
--------------------------------------------------------------------------------
  SELECT STATEMENT
    FILTER
      HASH GROUP BY
        HASH JOIN
          TABLE ACCESS BY INDEX ROWID ROLE
            INDEX RANGE SCAN N_ROLE_IDX2
          TABLE ACCESS FULL USER_ROLE
      TABLE ACCESS BY INDEX ROWID USER_ROLE
        INDEX UNIQUE SCAN U_USER_ROLE_IDX1
    FILTER
      HASH GROUP BY
        HASH JOIN
          TABLE ACCESS BY INDEX ROWID ROLE
            INDEX RANGE SCAN N_ROLE_IDX2
          TABLE ACCESS FULL USER_ROLE
      TABLE ACCESS BY INDEX ROWID USER_ROLE
        INDEX UNIQUE SCAN U_USER_ROLE_IDX1

我没有足够的权限在桌面上运行统计数据

尝试了以下更改,但只缩短了1或2秒:

WITH CTE AS (SELECT b.status_id FROM USER_ROLE b 
                                  WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )  
        AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date 
                                        )) 
                                 )
    SELECT 
       r.user_id, r.role_id, r.participant_code, MAX(status_id) 
      FROM 
        user_role r, 
        cmp_role c 
      WHERE 
        r.role_id = c.role_id 
        AND r.participant_code IS NOT NULL 
        AND c.group_id = 3 
        GROUP BY 
        r.user_id, r.role_id, r.participant_code 
        HAVING MAX(status_id) IN (select * from CTE)
  • 收集表格的统计数据
  • 解释查询计划并显示结果
  • 收集表格的统计数据
  • 解释查询计划并显示结果

  • 首先是子查询

    SELECT b.status_id FROM USER_ROLE b 
    WHERE (b.ACTIVE = 1 
            OR ( b.ACTIVE IN ( 0,3 )  
            AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date )
          )
    
    除了全表扫描之外,没有其他方法可以获得该结果。 您可能缺少一个连接,但不知道您希望查询做什么,我们无法告诉您


    其次,根据组id为3的cmp_角色记录的比例,以及与这些角色不匹配的用户_角色的比例,在那里进行完整扫描可能会更好。例如,如果27个cmp_角色记录中有3个在组3中,并且100000个用户_角色记录与这些cmp_角色记录匹配,那么对表进行一次扫描可能比执行100000个索引查找更有效。

    首先,您有子查询

    SELECT b.status_id FROM USER_ROLE b 
    WHERE (b.ACTIVE = 1 
            OR ( b.ACTIVE IN ( 0,3 )  
            AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date )
          )
    
    除了全表扫描之外,没有其他方法可以获得该结果。 您可能缺少一个连接,但不知道您希望查询做什么,我们无法告诉您


    其次,根据组id为3的cmp_角色记录的比例,以及与这些角色不匹配的用户_角色的比例,在那里进行完整扫描可能会更好。例如,如果27个cmp_角色记录中有3个在组3中,并且100000个用户_角色记录与这些cmp_角色记录匹配,然后,对表进行一次扫描可能比进行100000次索引查找更有效。

    我认为以下方法会起作用。我本以为子查询只会计算一次,因为它不相关-似乎不是这样。我在sh演示模式中对sales表进行了类似的查询(简单)。我对它进行了修改,使用了具体化的CTE方法,它只运行了1秒,而不是18秒。有关方法,请参见下文。速度快了10倍

    with cte as (
    select /*+materialize*/  max(amount_sold) from sales)
    select prod_id,sum(amount_sold) from
    sales
    group by prod_id
    having max(amount_sold) in(
    select * from cte)
    /
    
    因此,在您的例子中,您将子查询具体化为

    with CTE as (
        SELECT /*+ materialize */ b.status_id FROM USER_ROLE b 
                                      WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )  
            AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date 
                                            )) 
                                     )
    )
    

    然后在主查询中从CTE中选择。我认为以下方法会起作用。我原以为子查询只会被计算一次,因为它不相关-情况似乎不是这样。我在sh演示模式中对sales表尝试了类似的查询(简单)。我对它进行了修改,使用了具体化的CTE方法,它只运行了1秒,而不是18秒。有关方法,请参见下文。速度快了10倍

    with cte as (
    select /*+materialize*/  max(amount_sold) from sales)
    select prod_id,sum(amount_sold) from
    sales
    group by prod_id
    having max(amount_sold) in(
    select * from cte)
    /
    
    因此,在您的例子中,您将子查询具体化为

    with CTE as (
        SELECT /*+ materialize */ b.status_id FROM USER_ROLE b 
                                      WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )  
            AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date 
                                            )) 
                                     )
    )
    

    然后从主查询中的CTE中进行选择

    ,这样您的查询当前需要16.5秒,并且您希望它运行得更快。要做到这一点,你需要知道这16.5秒花在哪里。Oracle数据库的检测非常好,因此您可以非常详细地看到它在做什么。你可以查看我在OTN论坛上写的这个帖子:

    不知道你的时间花在哪里,所有的努力都只是猜测

    问候,,
    Rob.

    因此,您的查询当前需要16.5秒,您希望它运行得更快。要做到这一点,你需要知道这16.5秒花在哪里。Oracle数据库的检测非常好,因此您可以非常详细地看到它在做什么。你可以查看我在OTN论坛上写的这个帖子:

    不知道你的时间花在哪里,所有的努力都只是猜测

    问候,,

    Rob。

    我没有足够的权限运行统计数据。解释计划屏幕截图我想发布,但我没有足够的分数(10)要求tp发布图片:(我提供了解释计划我没有足够的权限运行统计数据。解释计划屏幕截图我想发布,但我没有足够的分数(10)要求tp发布图片:(我已经提供了explain planFull表扫描不一定是坏事。它可能是获取数据的最有效的方式。此查询是否花费太多时间运行?还有,有多少不同的ACTIVE值?是的,运行需要19秒,并产生39392行。有6个不同的ACTIVE值,范围从0到5在您需要向cte select添加/*+materialze*/hint之前,请参阅我提供的示例完整表扫描不一定是件坏事。它可能是获取数据的最有效方式。此查询是否花费太多时间运行?还有,有多少不同的ACTIVE值?是的,运行需要19秒,并产生39392行。t这里有6个不同的活动值,范围从0到5,正如我前面提到的,您需要向cte选择添加/*+Materialize*/hint。请参见我提供的示例。在我的案例中,这种方法的时间为四倍。我没有您的表,所以我不能确定。但是当我尝试对sh数据库(918843)进行类似的选择时记录cte查询在几秒钟内完成,而另一个查询需要18秒。在您的情况下,cte查询不可能是最坏情况下的四倍,它应该会产生最小的降级。您是否在提示名称或其他内容上键入?针对900000条记录运行的查询(您的情况)应该在5秒内运行。抱歉,早上我发布评论时一定是做错了什么。我刚刚尝试了一下,大约花了16.5秒。我用新的查询编辑了问题。请注意,您没有使用/*+materialize*/提示进行预验证:)现在我知道为什么在我的pl/sql开发人员中删除了它。添加该提示会使查询真正爬行。这种方法会使我的时间缩短四倍。我没有你的表,所以我不能确定。但是当我尝试类似的对sh数据库(918843)的选择时,会记录cte查询