Выполнение заказа по индексированным и неиндексированным столбцам - PullRequest
3 голосов
/ 21 сентября 2019

Для SQL-запросов, таких как

select * from <TABLE_NAME> order by <COLUMN_NAME_INDEXED>

против

select * from <TABLE_NAME> order by <COLUMN_NAME_NOT_INDEXED>

будет ли производительность / стоимость одинаковыми или различными по отношению к реляционным дБм?

Ответы [ 3 ]

1 голос
/ 21 сентября 2019

Да, индекс действительно улучшает производительность ORDER BY.

Сортировка очень дорогая с точки зрения использования процессора и памяти.С другой стороны, индексы представляют данные в отсортированном виде.Когда существует правильный индекс, ваша СУБД будет (при определенных условиях) использовать его вместо выполнения сортировки в памяти.

1 голос
/ 21 сентября 2019

Я был довольно удивлен, обнаружив, что индекс может помочь (протестировано на Oracle 12.2).

Тестовая таблица с 1М строк:

create table demo_sort
( num_indexed      integer not null
, num_unindexed    integer not null
, str_indexed      varchar2(50) not null
, str_unindexed    varchar2(50) not null
, date_indexed     date not null
, date_unindexed   date );

insert /*+ append */ into demo_sort
     ( num_indexed
     , num_unindexed
     , str_indexed
     , str_unindexed
     , date_indexed
     , date_unindexed )
select num, num
     , str, str
     , dt,  dt
from   ( select round(dbms_random.value() * 1e5) as num
              , dbms_random.string('x',50) as str
              , date '2010-01-01' + numtodsinterval(dbms_random.value() * 1e5, 'HOUR') as dt
         from   dual connect by rownum <= 1e6 );

create index demo_sort_num_ix on demo_sort(num_indexed);
create index demo_sort_str_ix on demo_sort(str_indexed);
create index demo_sort_date_ix on demo_sort(date_indexed);

call dbms_stats.gather_table_stats(user, 'demo_sort');

Тестирование производительности с использованием SQL * Plus AUTOTRACE (показывает лучшее время для трех запусков).План выполнения по умолчанию и результирующая производительность были одинаковыми:

SQL> set autotrace trace exp stat
SQL> set timing on
SQL> select * from demo_sort order by str_unindexed;

1000000 rows selected.

Elapsed: 00:00:18.92

Execution Plan
----------------------------------------------------------
Plan hash value: 3213928767

----------------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |  1000K|   122M|       | 33771   (1)| 00:00:02 |
|   1 |  SORT ORDER BY     |           |  1000K|   122M|   139M| 33771   (1)| 00:00:02 |
|   2 |   TABLE ACCESS FULL| DEMO_SORT |  1000K|   122M|       |  5233   (1)| 00:00:01 |
----------------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
        135  recursive calls
          3  db block gets
      18627  consistent gets
      17242  physical reads
          0  redo size
  141711618  bytes sent via SQL*Net to client
     733933  bytes received via SQL*Net from client
      66668  SQL*Net roundtrips to/from client
          0  sorts (memory)
          1  sorts (disk)
    1000000  rows processed


SQL> select * from demo_sort order by str_indexed;

1000000 rows selected.

Elapsed: 00:00:19.06

Execution Plan
----------------------------------------------------------
Plan hash value: 3213928767

----------------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |  1000K|   122M|       | 33771   (1)| 00:00:02 |
|   1 |  SORT ORDER BY     |           |  1000K|   122M|   139M| 33771   (1)| 00:00:02 |
|   2 |   TABLE ACCESS FULL| DEMO_SORT |  1000K|   122M|       |  5233   (1)| 00:00:01 |
----------------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
        136  recursive calls
          3  db block gets
      18627  consistent gets
      17242  physical reads
          0  redo size
  141711618  bytes sent via SQL*Net to client
     733933  bytes received via SQL*Net from client
      66668  SQL*Net roundtrips to/from client
          0  sorts (memory)
          1  sorts (disk)
    1000000  rows processed

Однако, если намекнуть на использование индекса, производительность примерно на 40% выше (хотя мы по-прежнему говорим только о 11 секундах вместо 19 для сортировки1M строк - и это на моем ноутбуке, а не на сервере базы данных производственного уровня):

SQL> select /*+ index(d) */ * from demo_sort d order by str_indexed;

1000000 rows selected.

Elapsed: 00:00:11.04

Execution Plan
----------------------------------------------------------
Plan hash value: 2822485249

------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                  |  1000K|   122M|  1009K  (1)| 00:00:40 |
|   1 |  TABLE ACCESS BY INDEX ROWID| DEMO_SORT        |  1000K|   122M|  1009K  (1)| 00:00:40 |
|   2 |   INDEX FULL SCAN           | DEMO_SORT_STR_IX |  1000K|       |  7770   (1)| 00:00:01 |
------------------------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
    1074381  consistent gets
          0  physical reads
          0  redo size
  141711618  bytes sent via SQL*Net to client
     733933  bytes received via SQL*Net from client
      66668  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
    1000000  rows processed

Таким образом, избегая сортировки, компенсируемой необходимостью делать в 57 раз больше операций ввода-вывода, что приводит к скромному улучшению,(Похоже, что оптимизатор был так же удивлен, как и я, - обратите внимание, что вычисленная стоимость для индексного подхода в 30 раз выше).

Подводя итог, можно сказать, что два подхода:

  1. Считать все строки таблицы за один проход и выполнить сортировку результатов.

  2. Считать все строки из индекса за один проход и для каждогозапись индекса извлекает соответствующую строку из таблицы.

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

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

0 голосов
/ 21 сентября 2019

Это зависит.Для очень маленьких наборов данных алгоритм сортировки может занять очень мало времени - и для загрузки индекса и его использования требуются дополнительные затраты.

Для более чем нескольких строк, обычно упорядочениепо индексируемому столбцу будет намного эффективнее.Сортировка - это дорогостоящая операция. Напомню, что это O (n log (n)), и большинство алгоритмов требуют чтения и записи данных несколько раз.

Существует еще одно исключение для очень больших таблиц или в оченьограниченная памятьМожет возникнуть ситуация, называемая thrashing , когда страницы данных (для select *) не помещаются в памяти.Когда размер намного больше доступной памяти, вы можете оказаться в ситуации, когда каждая запись, вероятно, потребует чтения страницы, не находящейся в памяти.

Это имеет очень, очень плохую производительность - хуже, чем на самом деле сортировкаданные.

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

Однако в большинстве случаевиспользование индексированного столбца более эффективно.

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