Нахождение всех значений набора ниже min () подмножества - PullRequest
0 голосов
/ 19 февраля 2019

Я использую SQL Server 2014, и у меня есть следующая таблица

CREATE TABLE t_priority (
    Name     VARCHAR(50) UNIQUE,
    Priority INT NOT NULL
);

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

Вот мой текущий запрос

select t1.Name from t_priority t1 join 
(select min(Priority) as Priority, Name from t_priority where Name like 'foo%' ) t2 
on t1.Name != t2.Name 
and t1.Priority < t2.Priority;

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

Можно ли достичь одного и того же результата запроса, как указано выше, за одно сканирование?Я чувствую, что упорядочение и быстрый доступ к индексу были бы полезны, поэтому индекс по Приоритету?Это также было бы полезно для некоторых других запросов, которые я получил, где я получаю все имена, где приоритет равен параметризованному значению

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

Любые другие улучшения вышеуказанного запроса приветствуются:)

1 Ответ

0 голосов
/ 19 февраля 2019

Вы можете выразить это как:

select t.*
from (select t.*,
             min(case when name like 'foo%' then priority end) over () as min_foo_priority
      from t_priority t
     ) t
where priority < min_foo_priority;

Или:

select t.*
from t_priority t
where t.priority < (select min(tt.priority) from t_priority tt where tt.name like 'foo%');

Для этой версии вы можете создать индекс для t_priority(name, priority), и запрос может быть в состояниииспользуйте индекс.

Ваша интуиция, что вы можете сделать это за один просмотр, отключена.Что произойдет, если сканирование таблицы будет таким, что самая последняя строка будет с минимальным приоритетом для «foo»?До этого у вас не было достаточно информации, чтобы принять или отклонить строки.

Вы могли бы быть эффективными - но с помощью индекса.Подстановочные знаки на «foo» проблематичны, но вы можете справиться с этим с помощью постоянного вычисляемого столбца.Итак:

alter table t_priority add name3 as (left(name, 3)) persisted;

create index idx_priority_name3_priority on t_priority(name3, priority);

Затем используйте name3 в запросе.Например:

select t.*
from t_priority t
where t.priority < (select min(tt.priority) from t_priority tt where tt.name3 = 'foo');
...