2016-12-21 6 views
6

У меня есть две таблицы со столбцом SessionOrder. Этот столбец представляет собой целочисленный тип данных и имеет следующий индекс: CREATE INDEX OSIDX_<internal name> ON <Entity>.INNER JOIN performance with '<' or '>' Условие

Я, выполнив следующий запрос:

SELECT i_0.rn, i_1.rn 
FROM (
    SELECT "RawEvent"."SessionOrder" as rn 
    FROM "RawEvent" i_0 
    WHERE something = 12 
) 
INNER JOIN (
    SELECT "RawEvent"."SessionOrder" as rn 
    FROM "RawEvent" i_1 
    WHERE something = 14 
) ON i_0.rn > i_1.rn 

Проблема этого запроса является ON i_0.rn > i_1.rn, что становится слишком медленным и раз вне. Я заменил его на ON i_0.rn = i_1.rn, и он был очень быстрым, но, очевидно, не дал ожидаемых результатов.

Кто-нибудь знает, как повысить производительность этого запроса, избегая тайм-аута? Другой целью этого вопроса является понять, почему он плохо работает с ON i_0.rn > i_1.rn.

PS: Это не возможно, чтобы увеличить время тайм-аута

+1

Что показывает план выполнения? Сколько строк занимает каждый подзапрос? (Почему вы используете подзапросы, а не просто присоединяетесь к таблицам, и на данный момент это не похоже на синтаксис Oracle). –

+0

Это недопустимый запрос. Алиасы таблиц не определены в области 'ON i_0.rn> i_1.rn' –

+3

Я согласен с Алексом, это определенно не синтаксис Oracle. Тем не менее, это почти декартово соединение. Вы действительно собираетесь присоединяться к каждой строке меньше, чем i_o.rn, к i_o? В качестве примера этот SQL возвращает 4 950 строк: с aset as (выберите rownum r из dba_objects, где rownum <101) выберите a.r, b.r из aset a внутреннее соединение aset b на a.r> b.r. –

ответ

3

Пожалуйста, проверьте сначала, если вы действительно использовать базу данных Oracle. Синтаксис вашего SQL предполагает либо другую СУБД, либо некоторую предшественницу.

Чтобы получить представление о том, что вы можете ожидать от таких запросов, вы можете использовать фиктивный пример следующим образом.

Генерация образца данных

create table myTab as 
with mySeq as 
(select rownum SessionOrder from dual connect by level <= 10000) 
select 12 something, SessionOrder from mySeq union all 
select 14 something, SessionOrder from mySeq 
; 

Это производит как субисточников каждый с 10.000 последовательностей, начиная от 1 до 10000.

Тест Запрос

create table myRes as 
select a.SessionOrder rn0, b.SessionOrder rn1 
from myTab a join myTab b on a.SessionOrder > b.SessionOrder and 
a.something = 12 and b.something = 14; 

Производит 49.995.000 строки в менее 30 секунд.

Если вы ожидаете получить такой большой результат за меньшее время, вам понадобится усовершенствованная оптимизация. Не зная ваших данных и требований, никаких общих советов не существует.

1

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

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

SELECT i_0."SessionOrder", i_1."SessionOrder" 
FROM "RawEvent" i_0 
INNER JOIN "RawEvent" i_1 ON i_0."SessionOrder" < i_1."SessionOrder" 
WHERE i_0."something" = 12 AND i_1."something" = 14 
+2

Этот запрос не возвращает те же результаты, что и исходный, вам придется заменить 'OR' на' AND', чтобы получить те же результаты. Кроме того, без дополнительной информации о ваших входных данных (количество строк, распределение чего-либо/SessionOrder) невозможно определить, будет ли иметь значение, если оптимизатор использовал индекс. Возможно, очень хорошо решить, что полное сканирование таблицы более подходит, если ваши данные сильно искажены. –

+0

@Helder Я добавил еще один ответ, обратившийся к вашему индексу. –

0

Ваш запрос выполняет три задачи:

1) выборки данных для обоих подмножеств (12 и 14)

2) Регистрация данных и

3) передать результат в клиент

Обратите внимание, что доступ к индексу (который вы подозреваете, чтобы вызвать проблемы) имеет значение только для шага 1. Таким образом, чтобы получить лучшее впечатление, прежде всего, реализовать распределение времени, прошедшего между тремя шагами. Это может быть сделано с помощью SQL * Plus (я использую те же сгенерированные данные, как и в предыдущем ответе)

Доступ к данным

Как мой стол не имеет индекс, выполняя COUNT (*) выполняет ПОЛНЫЙ ТАБЛИЦЫ. Поэтому в худшем случае для получения данных используется дважды в два раза.

SQL> set timi on 
SQL> set autotrace on 
SQL> select count(*) from mytab; 

    COUNT(*) 
---------- 
    20000 

Elapsed: 00:00:01.13 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3284627250 

-------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Cost (%CPU)| Time  | 
-------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  |  1 | 5472 (1)| 00:00:01 | 
| 1 | SORT AGGREGATE |  |  1 |   |   | 
| 2 | TABLE ACCESS FULL| MYTAB | 20000 | 5472 (1)| 00:00:01 | 
-------------------------------------------------------------------- 

ФСТ готова примерно на одну секунду, поэтому, чтобы получить обе группы приблиз. прошло две секунды.

РЕГИСТРИРУЙТЕСЬ

истекшее время для присоединиться к банку путем моделируется с CTAS джойна запроса.

SQL> create table myRes as 
    2 select a.SessionOrder rn0, b.SessionOrder rn1 
    3 from myTab a join myTab b on a.SessionOrder > b.SessionOrder and 
    4 a.something = 12 and b.something = 14; 

Table created. 

Elapsed: 00:00:23.65 

Регистрация возвращает около 50М строк (из-за больше, чем условие) и занимает около 21 секунд (я вычитаем 2 секунды для доступа к данным).

передает данные Клиента

Мы используем опцию set autotrace traceonly для подавления вывода запроса на экране клиента, но данные передаются, поэтому мы можем измерять время. (Если вы предоставляете результат на экране, время будет даже намного выше)

SQL> SET ARRAYSIZE 5000 
SQL> set autotrace traceonly 
SQL> select a.SessionOrder rn0, b.SessionOrder rn1 
    2 from myTab a join myTab b on a.SessionOrder > b.SessionOrder and 
    3 a.something = 12 and b.something = 14; 

49995000 rows selected. 

Elapsed: 00:03:03.89 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2857240533 

----------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
----------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  | 49M| 667M| 11077 (2)| 00:00:01 | 
| 1 | MERGE JOIN   |  | 49M| 667M| 11077 (2)| 00:00:01 | 
| 2 | SORT JOIN   |  | 10000 | 70000 | 5473 (1)| 00:00:01 | 
|* 3 | TABLE ACCESS FULL| MYTAB | 10000 | 70000 | 5472 (1)| 00:00:01 | 
|* 4 | SORT JOIN   |  | 10000 | 70000 | 5473 (1)| 00:00:01 | 
|* 5 | TABLE ACCESS FULL| MYTAB | 10000 | 70000 | 5472 (1)| 00:00:01 | 
----------------------------------------------------------------------------- 

Здесь самое время потратить около 2:40 минут

Резюме

Так в сценарии из общей сложности 3 минуты + только около 2 секунд тратят на доступ к данным (или около 1%). Даже если вы разрезаете доступ к данным до десятой части, вы не увидите практически никакой разницы. Проблема заключается в соединении и даже больше в передаче данных клиенту.

Когда индекс может помочь

И, конечно, это зависит от ...

В особом случае, когда у вас есть очень большой стол с очень маленькими данными с something in (12,14) вы можете прибыль от индекс, определенный на что-то И SessionOrder. Это позволяет использовать только только доступ к обходному доступу к данным вообще.