Усовершенствовать этот запрос, который использует 3 соединения в Oracle, может быть, используя «разделение поверх»? - PullRequest
1 голос
/ 14 марта 2012

У меня есть запрос, который не выполняется так, как я хочу, чтобы он выполнялся. Я использую его почти на всех страницах, чтобы отобразить в нижнем колонтитуле список из 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 ]

2 голосов
/ 15 марта 2012

Как предположил Энди Финкенштадт, вам лучше выбрать 4 случайных преподавателя, а затем выбрать 4 случайных значения из оставшегося набора результатов. Хотя это означает, что вы упорядочиваете по dbms_random.value дважды - что выглядит хуже - это означает, что наборы данных, по которым вы делаете это упорядочение, намного меньше.

Вы также должны убедиться в наличии индексов согласно ответу Рэнди .

Pet peeve, " для создания имен столбцов в оболочке, если у вас нет очень веской причины для этого, это никогда не стоит дополнительных хлопот, которые оно вызывает Для начала вам всегда придется ссылаться на них с кавычками.

Если вы хотите попробовать использовать аналитические функции, которые могут ускорить процесс, вы должны добавить distinct в выборку с 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
2 голосов
/ 14 марта 2012

для начинающих - как ваши показатели?

у вас должны быть индексы на

users.id
files.id
tutor_profiles.user_id
tutor_profiles.id
courses.tutor_id
users.avatar_id

после этого (на самом деле, может быть, до этого), что показывает план объяснения?

сколько записей примерно в таблицах?

...