Oracle: эффективное условие where для фильтрации столбца меток времени для получения всех записей указанного c дня - PullRequest
1 голос
/ 09 марта 2020

У меня есть месячная секционированная таблица в Oracle по столбцу отметки времени. Эта таблица содержит> 1 млрд строк из данных истории 2019 года. Теперь я хочу отфильтровать эту таблицу, чтобы получить все результаты за определенный c день, относительно части HH24:MI:SS.

Проблема (# 1), с которой я сталкиваюсь, заключается в том, что при использовании TO_CHAR(TIMESTAMPCOLUMN, 'YYYY-MM-DD'), время выполнения моих запросов увеличивается за последние месяцы. Пример:

SELECT * FROM BIG_PART_TABLE WHERE TO_CHAR(TIMESTAMPCOLUMN, 'YYYY-MM-DD') = '2019-01-01' --  3 sec
SELECT * FROM BIG_PART_TABLE WHERE TO_CHAR(TIMESTAMPCOLUMN, 'YYYY-MM-DD') = '2019-02-01' --  6 sec
SELECT * FROM BIG_PART_TABLE WHERE TO_CHAR(TIMESTAMPCOLUMN, 'YYYY-MM-DD') = '2019-12-01' -- 36 sec

Итак, я избавился от TO_CHAR и начал фильтровать так:

SELECT * FROM BIG_PART_TABLE WHERE TIMESTAMPCOLUMN BETWEEN DATE '2019-01-01' AND DATE '2019-01-02'  -- 0.032 sec
SELECT * FROM BIG_PART_TABLE WHERE TIMESTAMPCOLUMN BETWEEN DATE '2019-12-01' AND DATE '2019-12-02'  -- 0.031 sec

Проблема (# 2) в том, что мне лень написать предложение BETWEEN, за исключением того факта, что это увеличивает вероятность ошибок.

Наконец, я действительно хочу использовать эффективное предложение where для фильтрации моей таблицы, например:

SELECT * FROM BIG_PART_TABLE WHERE TIMESTAMPCOLUMN = DATE '2019-01-01'

Спасибо за все.

Ответы [ 4 ]

3 голосов
/ 09 марта 2020

Правильный подход - не использовать функции даты в столбце даты - использование таких функций делает запрос не SARGable, что означает, что он не может использовать индекс индекса в столбце даты.

Нет синтаксический сахар, который сделает выражение короче, чтобы писать.

Я бы также предложил использовать полуоткрытые интервалы вместо between:

WHERE 
    TIMESTAMPCOLUMN >= DATE '2019-01-01'
    AND TIMESTAMPCOLUMN < DATE '2019-01-02'

BETWEEN включительно на обоих концах, так что ваше выражение подразумевает, что отметки времени на 2019-01-02 00:00:00 будут отфильтрованы, в то время как это, скорее всего, не то, что вы хотите.

1 голос
/ 10 марта 2020

Используйте синтаксис partition_extension_clause:

SELECT *
  FROM BIG_PART_TABLE PARTITION FOR (DATE '2019-12-01')
 WHERE TRUNC(TIMESTAMPCOLUMN) = DATE '2019-12-01' ;

Этот код все еще немного запутан. Но по крайней мере этот синтаксис позволяет использовать один и тот же литерал даты вместо того, чтобы создавать совершенно новое выражение даты. И хотя в коде есть дублирование, дублирование немного самодокументируется: первое выражение должно использовать сокращение разделов для поиска ближайшего сегмента, второе выражение - для получения точных строк.

1 голос
/ 09 марта 2020

Чтобы использовать разделение, Oracle должен распознать ключ разделения. Если он использует полную временную метку, то у вас может быть проблема.

Существует разумный шанс, что он использует trunc(TIMESTAMPCOLUMN) или trunc(TIMESTAMPCOLUMN, 'DD'). Если это так, то вы можете использовать это

WHERE TRUNC(TIMESTAMPCOLUMN) = DATE '2019-01-01' 

Как только вы это выясните, вы можете добавить вычисляемый столбец в таблицу, чтобы вы получили:

alter table big_part_table add column timestampcolumn_date as trunc(timestampcolumn);

Затем вы можете использовать timestampcolumn_date в предложении WHERE.

0 голосов
/ 09 марта 2020

Самый быстрый способ доступа к данным в Orace - использовать имя раздела.

Как в этом примере:

 select * from BIG_PART_TABLE partition(ParititonName);
...