2014-02-18 2 views
1

Я работаю над запросом (Oracle 11g), который выполняет много манипуляций с датами. Используя генератор строк, я проверяю каждую дату в диапазоне дат для каждой записи в другой таблице. По другому запросу я знаю, что генератор строк должен генерировать 8500 дат, и эта сумма будет расти на 365 дней в год. Кроме того, таблица, которую я изучаю, имеет около 18000 записей, и эта таблица, как ожидается, будет расти на несколько тысяч записей в год.Как избежать дорогого декартова продукта с использованием генератора строк

Проблема возникает при присоединении генератора строк к другой таблице, чтобы получить диапазон дат для каждой записи. Советник SQLTuning говорит, что есть дорогостоящий декартово продукт, который имеет смысл, учитывая, что запрос в настоящее время может генерировать до 8500 x 18000 записей. Вот запрос в усеченной форме, без всякой логики даты и т.д .:

with n as (
    select level n 
    from dual 
    connect by level <= 8500 
) 
select t.id, t.origdate + n origdate  
from (
    select id, origdate, closeddate 
    from my_table 
) t 
join n on origdate + n - 1 <= closeddate -- here's the problem join 
order by t.id, t.origdate; 

Есть ли альтернативный способ соединить эти две таблиц без декартова произведения?

Мне нужно рассчитать прошедшее время для каждой из этих записей, запретить выходные и федеральные праздники, чтобы я мог сортировать по прошедшему времени. Кроме того, разбиение на страницы таблицы выполняется на стороне сервера, поэтому мы не можем просто загружать в таблицу и сортировать клиентскую сторону.

Максимальный возраст записи в системе сейчас составляет 3656 дней, а средний - 560, поэтому это не так плохо, как 8500 x 18000; но все равно плохо.

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

+0

Не могли бы вы объяснить, почему вам нужно создать столько записей? 8500 x 18000 = 15.300.000 строк, оно должно быть медленным. – krokodilko

+0

@kordirko, см. Мои правки выше. – earachefl

ответ

0

Я думаю, что вы получите лучшую производительность, если вы немного переписать условие соединения:

with n as (
    select level n 
    from dual 
    connect by level <= 8500 
) 
select t.id, t.origdate + n origdate  
from (
    select id, origdate, closeddate 
    from my_table 
) t 
join n on Closeddate - Origdate + 1 <= n --you could even create a function-based index 
order by t.id, t.origdate; 
+0

, что помогло немного, спасибо, но не достаточно близко. – earachefl

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

  • Нет связанных вопросов^_^