Как выбрать первые N записей из базы данных, содержащей миллион записей?
У меня есть база данных oracle, заполненная миллионами записей. Я пытаюсь написать SQL-запрос, который возвращает первые N" отсортированных записей ( скажем 100 записей) из базы данных, основанные на определенных условиях.
SELECT *
FROM myTable
Where SIZE > 2000
ORDER BY NAME DESC
затем программно выберите первые N записей.
проблема с этим подходом является :
- результаты запроса в полмиллиона записи и причины "порядок по имени" все записи, которые будут отсортированы по имени в порядке убывания. Эта сортировка занимает много времени. (почти на 30-40 секунд. Если я опущу ORDER BY, это займет всего 1 секунду).
- после того, как вид меня интересует только первые N (100) записей. Поэтому сортировка полных записей бесполезна.
мои вопросы:
- можно ли указать 'N' в сам запрос? ( это касается только N записей и запрос будет быстрее).
- любой лучший способ в SQL улучшить запрос для сортировки только Н элементы и возвращение в быстром время.
5 ответов
Если ваша цель-найти 100 случайных строк и сортировать их после Лассе!--5--> является правильным. Если, как я думаю, вы хотите, чтобы первые 100 строк были отсортированы по имени, отбрасывая другие, вы построили бы такой запрос:
SELECT *
FROM (SELECT *
FROM myTable
WHERE SIZE > 2000 ORDER BY NAME DESC)
WHERE ROWNUM <= 100
оптимизатор поймет, что это запрос TOP-N и сможет использовать индекс по имени. Ему не нужно будет сортировать весь результирующий набор, он просто начнется в конце индекса и прочитает его назад и остановится после 100 строк.
вы также можете добавить подсказку к исходному запросу, чтобы оптимизатор понял, что вас интересуют только первые строки. Это, вероятно, создаст аналогичный путь доступа:
SELECT /*+ FIRST_ROWS*/* FROM myTable WHERE SIZE > 2000 ORDER BY NAME DESC
Edit: просто добавив AND rownum <= 100
запрос не будет работать, так как в Oracle rownum приписывается до сортировка : вот почему вы должны использовать подзапрос. Без подзапроса Oracle выберет 100 случайных строк, а затем отсортирует их.
этой показывает, как выбрать первые n строк в зависимости от версии Oracle.
начиная с Oracle 9i, ранг () и Функции DENSE_RANK() можно использовать для определите верхние N строк. Примеры:
получите 10 лучших сотрудников на основе их жалованье!--3-->
выберите ename, sal FROM ( выбрать эмаль кулон, Сэл, ранг() над (приказ по АЛГ DESC) sal_rank От emp) где sal_rank
выберите сотрудников, входящих в топ-10 заработная плата
выберите ename, sal FROM ( выбрать ename, sal, DENSE_RANK() OVER (ORDER BY sal DESC) sal_dense_rank Из emp) где sal_dense_rank
разница между ними объясняется здесь
добавить это:
AND rownum <= 100
к вашему предложению WHERE.
однако, это не будет делать то, что вы просите.
Если вы хотите выбрать 100 случайных строк, отсортировать их, а затем вернуть их, вам придется сначала сформулировать запрос без порядка, затем ограничить его 100 строками, затем выбрать из этого и отсортировать.
этой мог бы работа, но, к сожалению, у меня нет сервера Oracle, доступного для тестирования:
SELECT *
FROM (
SELECT *
FROM myTable
WHERE SIZE > 2000
AND rownum <= 100
) x
ORDER BY NAME DESC
но обратите внимание на "случайная" часть там, вы говорите: "Дайте мне 100 строк с размером > 2000, мне все равно, какие 100".
Это действительно то, чего вы хотите?
и нет, вы фактически не получите случайный результат в том смысле, что он будет меняться каждый раз, когда вы запрашиваете сервер, но вы находитесь во власти оптимизатора запросов. Если статистика загрузки данных и индекса для этой таблицы изменяется со временем, в какой-то момент Вы можете получить другие данные, чем в предыдущем запросе.
ваша проблема заключается в том, что сортировка выполняется каждый раз при выполнении запроса. Операцию сортировки можно исключить с помощью индекса-оптимизатор может использовать индекс для исключения операции сортировки, если столбец сортировки объявлен не нулевым.
(Если столбец nullable, это все еще возможно, либо (a) добавив не нулевой предикат к запросу, либо (b) добавив индекс на основе функции и соответствующим образом изменив предложение ORDER BY).
просто для справки, в Oracle 12c эта задача может быть выполнена с помощью FETCH
предложения. Вы можете видеть здесь для примеров и дополнительных ссылок на ссылки по этому вопросу.