Подтвердить что ты не робот

Могу ли я оптимизировать запрос SELECT DISTINCT x FROM largeTable, создав индекс в столбце x?

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

Мне нужно сделать запрос типа SELECT DISTINCT x FROM hugeTable, и я хочу сделать это относительно быстро.

Я сделал что-то вроде CREATE INDEX hugeTable_by_x ON hugeTable(x), но по какой-то причине, хотя вывод мал, выполнение запроса происходит не так быстро. План запроса показывает, что 97% времени тратится на сканирование индексов hugeTable_by_x, при этом количество строк равно размеру всей таблицы. Далее следует, в частности, операция Hash Match.

Поскольку я создал индекс в столбце x, не могу ли я ожидать, что этот запрос будет работать очень быстро?

Обратите внимание, что я использую Microsoft SQL Server 2005.

4b9b3361

Ответ 1

Это, скорее всего, не проблема индексирования, а одно из данных. Нормализация, если быть точным. Тот факт, что вам нужно запрашивать различные значения поля и даже желать добавить индекс, является сильным индикатором того, что поле должно быть нормализовано в отдельную таблицу с (маленьким) ключом соединения. Затем различные значения будут доступны сразу, сканируя гораздо меньшую внешнюю таблицу поиска.

Update
В качестве обходного пути вы можете создать индексированное представление по совокупности в поле 'different'. COUNT_BIG - это совокупность, разрешенная в индексированных представлениях:

create view vwDistinct
with schemabinding
as select x, count_big(*)
from schema.hugetable
group by x;

create clustered index cdxDistinct on vwDistinct(x);

select x from vwDistinct with (noexpand);

Ответ 2

SQL Server не реализует никаких средств для прямого поиска следующего отдельного значения в индексе, пропускающего дубликаты по пути.

Если у вас много дубликатов, вы можете использовать рекурсивный CTE для имитации этого. Техника происходит от здесь. ("Сверхбыстрый DISTINCT с использованием рекурсивного CTE"). Например:

with recursivecte as (
  select min(t.x) as x
  from hugetable t
  union all
  select ranked.x
  from (
    select t.x,
           row_number() over (order by t.x) as rnk
    from hugetable t
    join recursivecte r
      on r.x < t.x
  ) ranked
  where ranked.rnk = 1
)
select *
from recursivecte
option (maxrecursion 0)

Ответ 3

Если вы знаете значения заранее и есть индекс в столбце x (или если каждое значение, скорее всего, появится быстро при сканировании seq всей таблицы), гораздо быстрее запросить каждый отдельно:

select vals.x
from [values] as vals (x)
where exists (select 1 from bigtable where bigtable.x = vals.x);

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

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

Ответ 4

Нет. Но есть некоторые обходные пути (исключая нормализацию):

Как только индекс окажется на месте, тогда его можно реализовать в SQL, что оптимизатор может делать автоматически:

fooobar.com/questions/302300/... (упоминаются многочисленные обходные пути)

Другие ответы говорят, что вы можете нормализовать, что бы решить вашу проблему, но даже когда нормализованный SQL Server по-прежнему любит выполнять сканирование, чтобы найти max() внутри группы (групп). Обходные:

https://dba.stackexchange.com/questions/48848/efficiently-query-max-over-multiple-ranges?rq=1

Ответ 5

При выполнении SELECT DISTINCT в индексированном поле сканирование индекса имеет смысл, поскольку выполнение все равно должно проверять каждое значение в индексе для всей таблицы (при условии отсутствия предложения WHERE, как это имеет место ваш пример).

Индексы обычно оказывают большее влияние на условия WHERE, JOINS и ORDER BY.

Ответ 6

Согласно вашему описанию плана выполнения, я считаю, что это наилучшее выполнение.

Index Scan считывает весь индекс как хранящийся (не в индексном порядке), HASH MATCH делает отдельный.

Могут быть другие способы решения вашей проблемы. В SQL Server индексированные представления приходят мне в голову. Однако это может дать вам большой успех для записи на эту таблицу.

Ответ 7

Возможно. Хотя это не гарантировано - это полностью зависит от запроса.

Я предлагаю прочитать эту статью Гейл Шоу (часть 1 и часть 2).