SQL Индекс сервера и плохой план выполнения - PullRequest
0 голосов
/ 24 марта 2020

У меня есть существующая SQL Серверная база данных, где я не могу изменить структуру или запросы выполнялись, и столкнулся с проблемой, связанной с плохим выполнением, влияющим на производительность и, в конечном итоге, на стоимость облачной базы данных.

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

Проблема

У меня есть две таблицы: Table1 и Table2. Table2 ссылается на Table1 через поле TABLE1_ID, и мы запускаем запрос SQL, извлекающий информацию из Table2 при фильтрации на Table1 (INNER JOIN, я полагаю).

Используя следующий запрос:

DECLARE @P1 datetime
DECLARE @P2 datetime

SELECT
    dbo.Table2.VALUE
FROM
    dbo.Table2,
    dbo.Table1
WHERE
    -- joins Table1/Table2
        dbo.Table1.ID = dbo.Table2.TABLE1_ID 

     -- filters on Table1
    AND dbo.Table1.TIMESTAMP between @P1 and @P2

Насколько я понимаю, ядро ​​базы данных сначала отфильтрует по Table1, а затем выполнит объединение с Table2, однако план выполнения I Я вижу, что Merge Join подразумевает, что Table2 полностью сканируется, затем объединяется с отфильтрованными результатами из Table1.

enter image description here

Что я пробовал

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

  1. Попытка оптимизации Создание ограничения FK
  2. Попытка оптимизации Создание других индексов с / без включаемых столбцов
  3. Идентификация проблемы Изменение запроса для выбора значения как Table1 и Table2 и увидеть разницу

Повторное создание проблемы

Следующий скрипт может позволить вам воссоздать структуру базы данных (обратите внимание, что она вставит 1M записей в обе таблицы):

CREATE TABLE [dbo].[Table1] (
    [ID] [decimal](10, 0) IDENTITY(1,1) NOT NULL,
    [VALUE] [nchar](10) NULL,
    [TIMESTAMP] [datetime] NOT NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Table1] ADD  CONSTRAINT [DF_Table1_TIMESTAMP]  DEFAULT (sysdatetime()) FOR [TIMESTAMP]
GO

CREATE UNIQUE CLUSTERED INDEX [IX_Table1_ID] ON [dbo].[Table1]
(
    [ID] ASC
)
GO

CREATE NONCLUSTERED INDEX [IX_Table1_TIMESTAMP] ON [dbo].[Table1]
(
    [TIMESTAMP] ASC
)
INCLUDE ([ID])
GO

CREATE TABLE [dbo].[Table2] (
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [TABLE1_ID] [decimal](10, 0) NOT NULL,
    [VALUE] [nchar](10) NULL
) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_Table2_TABLE1_ID] ON [dbo].[Table2]
(
    [TABLE1_ID] ASC
) INCLUDE ([VALUE])
GO

Declare @Id decimal(10,0) = 1
DECLARE @Now datetime = SYSDATETIME()

While @Id <= 1000000
Begin 
   Insert Into dbo.Table1 values ('T1_' + CAST(@Id as nvarchar(10)), DATEADD (ss, @Id, @Now))
   Insert Into dbo.Table2 values (@Id, 'T2_' + CAST(@Id as nvarchar(10)))
   Print @Id
   Set @Id = @Id + 1
End
GO

Тогда вы можете попробовать т o выполнить следующий запрос:

DECLARE @P1 datetime
DECLARE @P2 datetime

SELECT
    dbo.Table2.VALUE
FROM
    dbo.Table2,
    dbo.Table1
WHERE
        dbo.Table1.ID = dbo.Table2.TABLE1_ID
    AND dbo.Table1.TIMESTAMP between @P1 and @P2

1 Ответ

2 голосов
/ 24 марта 2020

Насколько я понимаю, ядро ​​базы данных сначала отфильтровывает таблицу 1, а затем выполняет объединение с таблицей 2,

Неверно. SQL является описательным языком, а не процедурным языком. Запрос SQL описывает набор результатов, а не методы, используемые для его создания.

Анализатор и оптимизатор SQL отвечают за создание плана выполнения. Единственное требование - чтобы результаты из плана выполнения соответствовали результатам, описанным в запросе.

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

На самом деле ваш запрос читает index . Это более эффективный способ «фильтрации» данных, чем собственно чтение данных и фильтрация. Это выглядит как оптимальный план выполнения.

Кроме того, не используйте запятые в предложении FROM. Используйте правильный, явный, стандартный , читаемый JOIN синтаксис.

...