Как улучшить производительность SQL-запроса, который имеет UNION и sub-select? - PullRequest
0 голосов
/ 25 ноября 2011

У меня есть взгляд на mssql 2008. Коды T-SQL, как показано ниже,

SELECT     *
FROM        View1
WHERE     Category = 1
UNION ALL
SELECT     *
FROM         View1 AS Level#1
WHERE    Category = 2 AND NOT EXISTS
                          (SELECT     *
                            FROM          View1
                            WHERE      Level#1.Code = Code AND CategoryCode = 1)

P.S. для кодов; Тип данных кода - nvarchar - View1 - тот же самый вид

Когда я выполняю этот код из примерно 3500 записей, результаты появляются на экране более чем за 5 минут.

Как я могу изменить этот код для быстрого выполнения? Спасибо уже сейчас за ваши предложения.

Ответы [ 4 ]

1 голос
/ 25 ноября 2011

Ваша проблема (с предоставленной информацией) является представлением и SELECT *

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

  • SELECT * также означает, что индексы не будут использоваться эффективно, если вообще будут использоваться. Вы получите сканы или ключевые поиски в плане выполнения, потому что вы не можете использовать закрывающие индексы и т. П.

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

0 голосов
/ 25 ноября 2011

Не уверен на 100%, что я понимаю ваш запрос, но попробуйте это и посмотрите, получите ли вы те же (ожидаемые) результаты:

SELECT     *
FROM        View1
WHERE     Category = 1
UNION ALL
SELECT     *
FROM         View1 AS Level#1
LEFT JOIN View1 as XX ON Level#1.code=XX.Code and XX.CategoryCode =1 
WHERE    Level#1.Category = 2 AND xx.code is NULL
0 голосов
/ 25 ноября 2011

Если вы используете SQL Server 2005 или более позднюю версию, вы можете попробовать что-то вроде этого:

WITH ranked AS (
  SELECT
    *,
    rnk = RANK() OVER (PARTITION BY Code ORDER BY Category)
  FROM View1
  WHERE Category IN (1, 2)
)
SELECT
  *  /* this will include the 'rnk' column too;
        in any event, masked output is a very
        discouraged thing to do so you should
        probably specify the columns explicitly */
FROM ranked
WHERE rnk = 1

Если никогда не может быть более одного Code на Category, замените RANK() с ROW_NUMBER(), что должно быть более эффективным.

Полезное чтение:

0 голосов
/ 25 ноября 2011

Понятия не имею, какое у вас определение таблицы / индекса, поэтому я могу ошибаться, но на первый взгляд этот код кажется ненужным:

AND NOT EXISTS
                          (SELECT     *
                            FROM          View1
                            WHERE      Level#1.Code = Code AND CategoryCode = 1)

, поскольку у вас уже есть WHERE Category = 2 во втором предложении UNION ALL

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