改进在Oracle中使用3个连接的查询,也许使用“partition over”?

时间:2012-03-14 16:00:49

标签: oracle query-optimization

我的查询无法执行,因为我希望它执行。我几乎在所有页面上都使用它来在页脚中显示4个随机导师和他们的一些相关数据(他们的名字,他们的头像以及他们提供的课程数量)的列表。

如何在Oracle中提高此查询的执行速度?我在看分区并使用分区和其他东西。我有一个mySQL背景,我可能没有充分利用Oracle。

我有以下表结构:

tutor_profiles:
    id
    user_id (FK users)

 users:
     id
     username
     avatar_id (FK files)

 courses:
     id
     tutor_id (FK tutor_profiles)
     description
     ...

  files
      id
      file_uri

`

我有这个问题:

SELECT * FROM 
    (SELECT inner_query.*, rownum rnum 
    FROM (
        SELECT tutor_profiles.id AS "tutor_id"
            , tutor_profiles.full_name AS "full_name"
            , files.file_uri as "file_uri"
            , files.id AS file_id
            , tutor_profiles.user_id
            , count(distinct courses.id) AS "course_count" 
        FROM tutor_profiles 
            LEFT JOIN users ON users.id = tutor_profiles.user_id 
            LEFT JOIN files ON files.id = users.avatar_id 
            LEFT JOIN courses ON tutor_profiles.id = courses.tutor_id 
        GROUP BY tutor_profiles.id, tutor_profiles.full_name, tutor_profiles.user_id, files.file_uri, files.id 
        ORDER BY dbms_random.VALUE
    ) inner_query 
    WHERE rownum <= 4)

2 个答案:

答案 0 :(得分:2)

首发 - 您的索引如何?

你应该有

的索引
users.id
files.id
tutor_profiles.user_id
tutor_profiles.id
courses.tutor_id
users.avatar_id

之后(实际上可能在那之前),解释计划是什么?

表中大约有多少条记录?

答案 1 :(得分:2)

正如Andy Finkenstadt建议你最好选择4位随机导师,然后从剩下的结果集中选择4个随机值。虽然这意味着您按dbms_random.value两次排序 - 这看起来更糟糕 - 但这确实意味着您正在进行此排序的数据集要小得多。

您还应确保根据Randy's answer存在索引。

宠物小便,"来生成套管名称,除非你有非常这个好理由,从不值得因为它引起的额外麻烦。你总是必须用引号引用它们作为开始。

如果您想尝试使用分析函数,这可能会加快速度,您应该在distinct的select中添加count,并将count(distinct c.id)替换为count(distinct c.id) over ()。这意味着您为所有行计算distinct id。如果您添加了partition by子句,则可以对分区中的任何内容进行此计数。您还应该完全删除group by

我还删除了一个额外的子选择,这不是必需的。

select *
  from ( select tp.id as tutor_id
              , tp.full_name as full_name
              , f.file_uri as file_uri
              , f.id AS file_id
              , tp.user_id
              , count(distinct c.id) as course_count 
           from ( select *
                    from ( select id 
                                , full_name
                                , user_id
                             from tutor_profiles
                            order by dbms_random.value )
                   where rownum <= 4 ) tp
           left outer join users u
             on u.id = tp.user_id 
           left outer join files f
             on f.id = u.avatar_id 
           left outer join courses c
             on tp.id = c.tutor_id 
          group by tp.id, tp.full_name, tp.user_id, f.file_uri, f.id
          order by dbms_random.value )
 where rownum <= 4