2013-10-09 4 views
0

У меня очень большая таблица, состоящая из 40 миллионов строк, в базе данных SQL Server 2008.Как оптимизировать select top N Запрос

CREATE TABLE [dbo].[myTable](
    [ID] [bigint] NOT NULL, 
    [CONTRACT_NUMBER] [varchar](50) NULL, 
    [CUSTOMER_NAME] [varchar](200) NULL, 
    [INVOICE_NUMBER] [varchar](50) NULL, 
    [AGENCY] [varchar](50) NULL, 
    [AMOUNT] [varchar](50) NULL, 
    [INVOICE_MONTH] [int] NULL, 
    [INVOICE_YEAR] [int] NULL, 
    [Unique_ID] [bigint] NULL, 
    [bar_code] [varchar](50) NOT NULL, 
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED 
(
    [ID] ASC, 
    [bar_code] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

Я пытаюсь оптимизировать производительность для следующего запроса:

SELECT top 35 ID, 
      CONTRACT_NR, 
      CUSTOMER_NAME, 
      INVOICE_NUMBER, 
      AMOUNT, 
      AGENCY, 
      CONTRACT_NUMBER, 
      ISNULL([INVOICE_MONTH], 1) as [INVOICE_MONTH], 
      ISNULL([INVOICE_YEAR], 1) as [INVOICE_YEAR], 
      bar_code, 
      Unique_ID 
      from MyTable 
WHERE 
CONTRACT_NUMBER like @CONTRACT_NUMBER and 
INVOICE_NUMBER like @INVOICE_NUMBER and 
CUSTOMER_NAME like @CUSTOMER_NAME 
ORDER BY Unique_ID desc 

Для того, чтобы сделать это я построить включенный индекс по столбцам CONTRACT_NUMBER, INVOICE_NUMBER и CUSTOMER_NAME.

CREATE NONCLUSTERED INDEX [ix_search_columns_without_uniqueid] ON [dbo].[MyTable] 
(
    [CONTRACT_NUMBER] ASC, 
    [CUSTOMER_NAME] ASC, 
    [INVOICE_NUMBER] ASC 
) 
INCLUDE ([ID], 
[AGENCY], 
[AMOUNT], 
[INVOICE_MONTH], 
[INVOICE_YEAR], 
[Unique_ID], 
[Contract_nr], 
[bar_code]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 

По-прежнему выполняется запрос от 3 секунд до 10 секунд для выполнения. Из плана выполнения запроса я вижу, что выполняется операция поиска индекса, потребляющая около 30% общей рабочей нагрузки, а не операция Sort (Top N), которая потребляет остальные 70%. Любая идея, как я могу оптимизировать этот запрос, предпочтительнее время отклика менее 1 секунды? Примечание. Я попытался также включить столбец [Unique_ID] в столбцах индекса. В этом случае план выполнения запросов выполняет сканирование индекса, но со многими пользователями, запрашивающими базу данных, у меня такая же проблема.

+0

Создайте указатель в столбце, который хотите отсортировать. Однако самым быстрым способом является наличие «кластерного индекса» в столбце, который вы хотите отсортировать. Поскольку это невозможно, попробуйте простой индекс. – alzaimar

+0

В дополнение к созданию индексов замените предложение LIKE на метод FulltextSearch. – GriGrim

ответ

0

Попробуйте заменить кластеризованный индекс (в настоящее время на двух столбцах) одним только на unique_id (при условии, что он действительно уникален). Это поможет вам сортировать. Затем добавьте второй индекс покрытия - как вы пробовали - по трем столбцам, используемым в WHERE. Проверьте, что ваша статистика соответствует дате. У меня такое ощущение, что столбец bar_code на вашем ПК предотвращает запуск вашего вида как можно быстрее.

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

UPDATE: поскольку у вас есть ведущие символы, вы не сможете воспользоваться индексом на CONTRACT_NUMBER, INVOICE_NUMBER или CUSTOMER_NAME: как это было предложено GriGrim, единственной альтернативой здесь является использование полнотекстового поиска (CONTAINS ключевого слова и т.д.).

+0

Мои переменные содержат основные подстановочные знаки. Я не могу гарантировать, что столбец Unique_Id действительно уникален, и я предпочитаю не менять текущий дизайн таблицы. –

+0

Из плана выполнения запроса кажется, что запрос использует индекс, так как есть операция поиска индекса, возвращающая требуемые строки. Как указано выше, операция поиска индекса потребляет приблизительно 30% рабочей нагрузки, а остальные потребляются операцией SORT (Top N). –

0

Проверьте это page для более подробной информации.

  • Обновите статистику с полным сканированием, чтобы упростить работу оптимизатора.

UPDATE STATISTICS tablename WITH fullscan GO

  • Набор статистики времени, и выполнить следующий запрос

    SET STATISTICS time ON GO
    SELECT num_of_reads, num_of_bytes_read, num_of_writes, num_of_bytes_written FROM sys.dm_io_virtual_file_stats(DB_ID('tempdb'), 1) GO SELECT TOP 100 c1, c2,c3 FROM yourtablename WHERE c1<30000 ORDER BY c2 GO SELECT num_of_reads, num_of_bytes_read, num_of_writes, num_of_bytes_written FROM sys.dm_io_virtual_file_stats(DB_ID('tempdb'), 1) GO

Результат

CPU time = 124 ms, elapsed time = 91 ms 
Before Query execution 
num_of_reads   num_of_bytes_read num_of_writes  num_of_bytes_written 
-------------------- -------------------- -------------------- -------------------- 
725864    46824931328   793589    51814416384 
After Query execution 
num_of_reads   num_of_bytes_read num_of_writes  num_of_bytes_written 
-------------------- -------------------- -------------------- -------------------- 
725864    46824931328   793589    51814416384 

https://www.mssqltips.com/sqlservertip/2053/trick-to-optimize-top-clause-in-sql-server/

Смежные вопросы