Преобразовать произвольный SQL SELECT TOP (x) в SELECT COUNT (*)? - PullRequest
1 голос
/ 08 августа 2009

Я хочу иметь возможность принимать любой произвольный запрос SELECT TOP(X), который обычно возвращает большое количество строк (без ограничения X), и преобразовывать этот запрос в запрос, который подсчитывает, сколько строк было бы возвращено без TOP(X) (то есть SELECT COUNT(*)). Помните, я спрашиваю о произвольном запросе с любым количеством объединений, где предложения, группировка и т. Д.

Есть ли способ сделать это?


отредактировано для отображения синтаксиса с решением Шеннона:

1011 * т.е. *

`SELECT TOP(X) [colnames] FROM [tables with joins] 
 WHERE [constraints] GROUP BY [cols] ORDER BY [cols]`

становится

`SELECT COUNT(*) FROM 
 (SELECT [colnames] FROM [tables with joins] 
 WHERE [constraints] GROUP BY [cols]) t`

1 Ответ

3 голосов
/ 08 августа 2009

Встроенный вид:

select count(*)
from (...slightly transformed query...) t

... слегка преобразованный запрос ... is:

  1. Если в предложении select есть какие-либо столбцы без имен, например select ... avg(x) ..., выполните одно из следующих действий: 1) Псевдоним столбца, например avg(x) as AvgX, 2) Удалите столбец, но убедитесь, что хотя бы один столбец слева или мой любимый 3) Просто сделайте предложение select select 1 as C
  2. Удалить TOP из предложения select.
  3. Удалить 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 в каждой строке.

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