Встроенный вид:
select count(*)
from (...slightly transformed query...) t
... слегка преобразованный запрос ... is:
- Если в предложении
select
есть какие-либо столбцы без имен, например select ... avg(x) ...
, выполните одно из следующих действий: 1) Псевдоним столбца, например avg(x) as AvgX
, 2) Удалите столбец, но убедитесь, что хотя бы один столбец слева или мой любимый 3) Просто сделайте предложение select select 1 as C
- Удалить
TOP
из предложения select
.
- Удалить
order by
предложение.
EDIT 1 Исправлено путем добавления псевдонимов для встроенного представления и работы с безымянными столбцами в предложении select
.
РЕДАКТИРОВАТЬ 2 Но как насчет производительности? Разве для этого не требуется, чтобы БД выполняла большой запрос, которого я хотел бы избежать с помощью TOP (X)?
Не обязательно. может иметь место для некоторых запросов, что этот счетчик будет выполнять больше работы, чем TOP (x). И может иметь место в том случае, если для конкретного запроса вы могли бы ускорить эквивалентный подсчет, внеся дополнительные изменения, чтобы удалить работу, которая не нужна для окончательного подсчета. Но эти упрощения нельзя включить в общий метод, чтобы принимал любой произвольный запрос SELECT TOP (X), который обычно возвращал бы большое количество строк (без ограничения X), и преобразовывал этот запрос в запрос, который подсчитывает, сколько строки были бы возвращены без TOP (X).
А в некоторых случаях оптимизатор запросов может оптимизировать ненужные данные, чтобы БД не была для выполнения большого запроса.
Например, Проверка таблицы и данных с использованием SQL Server 2005:
create table t (PK int identity(1, 1) primary key,
u int not null unique,
string VARCHAR(2000))
insert into t (u, string)
select top 100000 row_number() over (order by s1.id) , replace(space(2000), ' ', 'x')
from sysobjects s1,
sysobjects s2,
sysobjects s3,
sysobjects s4,
sysobjects s5,
sysobjects s6,
sysobjects s7
Некластеризованный индекс в столбце u
будет намного меньше кластерного индекса в столбце PK
.
Затем настройте SMSS, чтобы показать фактический план выполнения для:
select PK, U, String from t
select count(*) from t
Первый выбор выполняет сканирование кластерного индекса, потому что он должен вернуть данные из листьев. Второй запрос выполняет сканирование индекса для меньшего некластеризованного индекса, созданного для ограничения уникальности для U.
Применяя преобразование первого запроса, мы получаем:
select count(*)
from (select PK, U, String from t) t
Выполнение этого и просмотр плана, индекс на U используется снова, точно такой же план, как и select count(*) from t
. Листья не посещаются, чтобы найти значения для String в каждой строке.