Как я могу сделать этот запрос быстрее? - PullRequest
1 голос
/ 10 января 2012

Я выполняю этот запрос в БД Oracle:

SELECT COUNT(1) FROM db.table WHERE columnA = 'VALUE' AND ROWNUM < 2

Нет индекса для столбца A, а в таблице много тысяч строк (возможно, миллионов). Есть около двадцати значений, которые должны быть возвращены, так что это не огромное возвращаемое множество Однако, поскольку он запускает полное сканирование таблицы, он занимает несколько эонов. Как я могу сделать это быстрее?

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

1 Ответ

4 голосов
/ 10 января 2012

Если вы ищете наличие строки, а не количество раз ее появления, то это будет более уместно:

SELECT 1 
  FROM DB.TABLE
 WHERE ColumnA = 'VALUE'
   AND ROWNUM = 1

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

Контрольный пример:

create table q8806566
( id        number not null,
  column_a  number not null,
  padding   char(256),  -- so all the rows aren't really short
  constraint pk_q8806566 primary key (id) 
    using index tablespace users
)
tablespace users;

insert into q8806566 -- 4 million rows
  (id, column_a, padding)
with generator as
(select --+ materialize
        rownum as rn from dba_objects 
  where rownum <= 2000)
select rownum as id, mod(rownum, 20) as column_a, 
       v1.rn as padding
  from generator v1
       cross join generator v2;

commit;

exec dbms_stats.gather_table_stats (ownname => user, tabname => 'q8806566');

Данные для column_A хорошо распределены и могут быть найдены в первых нескольких блоках для всех значений, поэтому этот запрос выполняется хорошо:

SELECT 1    
  FROM q8806566
 WHERE Column_A = 1 
   AND ROWNUM = 1;

Время выполнения менее 1 секунды и низкий уровень ввода-вывода - порядка 4 входов-выходов. Тем не менее, при поиске значения, которое НЕ присутствует, все меняется тревожно:

SELECT 1    
  FROM q8806566
 WHERE Column_A = 20
   AND ROWNUM = 1;

20-40 секунд времени выполнения и более 100 000 операций ввода-вывода.

Однако, если мы добавим индекс:

create index q8806566_idx01 on q8806566 (column_a) tablespace users;
exec dbms_stats.gather_index_stats (ownname => user, indname => 'q8806566_idx01');

Мы получаем время отклика менее 0,1 секунды и однозначные операции ввода-вывода в обоих запросах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...