2015-12-01 2 views
2

У меня есть большая таблица (строки ~ 200M), которая индексируется в числовом столбце Z. Также есть индекс в ключевом столбце, K.Поиск «следующих 25 строк» ​​в Oracle SQL на основе индексированного столбца

K Z 
= ========================================== 
1 0.6508784068583483336644518457703156855132 
2 0.4078768075307567089075462518978907890789 
3 0.5365440453204830852096396398565048002638 
4 0.7573281573257782352853823856682368153782 

Что мне нужно, чтобы найти 25 записей, «окружающих» данную запись. Например, «следующая» запись, начинающаяся с K = 3, будет K = 1, за которой следует K = 4.

У меня было несколько источников (в первую очередь this paper от некоторых людей в Университете штата Флорида), что SQL, как и следующее, должен работать. Нетрудно представить, что сканирование по индексированному столбцу в порядке возрастания или убывания было бы эффективным.

select * from (
    select * 
    from T 
    where Z >= [origin's Z value] 
    order by Z asc 
) where rownum <= 25; 

Теоретически это должно найти 25 "следующих" строк, и аналогичный вариант найдет 25 "предыдущих" строк. Однако это может занять несколько минут, и план объяснения последовательно содержит полное сканирование таблицы. Полное сканирование таблицы просто слишком дорого для моей цели, но я ничего не хочу предложить оптимизатору запросов воспользоваться индексом (короче, конечно, изменить «> =» выше на знак равенства, что указывает на то, что индекс присутствует и работает). Я пробовал несколько советов безрезультатно (index, index_asc в нескольких перестановках).

Является ли то, что я пытаюсь сделать невозможным? Если бы я пытался сделать это в большой структуре данных, над которой у меня было больше контроля, я бы построил связанный список по значениям индексированного столбца и дереву, чтобы найти правильную точку входа. Тогда перемещение списка было бы очень недорогим (да, возможно, мне придется запускать весь диск, чтобы найти записи, которые я ищу, но мне наверняка не пришлось бы сканировать всю таблицу).

Я добавлю, что для моего запроса важно, чтобы база данных, которую я использую, запускала Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit.

+0

Должно быть ясным. Если ваша таблица имеет 200 строк '1 .. 200' и ​​вы хотите, чтобы 25 ближайших к строке' 100', вы получите строки '88 .. 112'? Тот же случай. Что касается 25 ближайших к строке '5', будут строки' 1 ..25'? –

+2

Не уверен, что его скорость будет более высокой, но попробуйте «... ГДЕ ПРИНИМАЙТЕСЬ, ЧТО ЗАКАЗЫВАЕТСЯ, КАК ЕСТЬ МЕЖДУ 12 ПРЕКРАСНЫМИ И 13 СЛЕДУЮЩИМИ», если я это правильно понимаю – Mihai

+0

@JuanCarlosOropeza Извините, я не был предельно ясен о случаях краев или о фактическом диапазоне интерес. Мне действительно нужны 25 самых близких записей в любом направлении. В начале и конце таблицы я не слишком беспокоюсь о нехватке в одном или другом направлении. Число 25 также не установлено в камне, но оно предназначено в основном для аромата. Я считаю, что решение, которое решает проблему, будет применяться для разных диапазонов. – Eric

ответ

8

Я построил небольшой тестовый корпус с 10K строк. Когда я заполнил таблицу таким образом, что значения Z уже были упорядочены, точный запрос, который вы указали, имел тенденцию использовать индекс. Но когда я заполнил его случайными значениями и обновил статистику таблиц, он начал выполнять полное сканирование таблицы, по крайней мере, для некоторых значений n, превышающих 25. Таким образом, есть точка опроса, в которой оптимизатор решает, что объем работы будет делать поиск записей индекса, а затем найти соответствующие строки в таблице больше, чем объем работы для полного сканирования. (Конечно, это может быть неверно в его оценке, но это то, что он должен продолжать.)

Я заметил, что вы используете SELECT *, что означает, что запрос возвращает оба столбца. Это означает, что нужно иметь доступ к фактическим строкам таблицы, поскольку ни один из них не содержит оба столбца. Это может подтолкнуть оптимизатора к предпочтению полного сканирования таблицы для более крупных образцов. Если запрос может быть выполнен только из индекса, более вероятно, что он будет использовать этот индекс.

Возможно, вам действительно не нужно возвращать значения K. Если это так, я предлагаю вам изменить оба вхождения SELECT * на SELECT z. В моем тесте это изменение вызвало запрос, который выполнял полное сканирование таблицы, чтобы вместо этого использовать сканирование индекса (и вообще не получить доступ к самой таблице).

Если вам нужно включить K в результат поиска, попробуйте создать индекс на (Z, K). Этот индекс может использоваться для удовлетворения запроса без доступа к таблице.

Смежные вопросы