У меня есть существующая 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
.
Что я пробовал
Я попробовал следующее, пытаясь определить проблему или оптимизировать производительность:
- Попытка оптимизации Создание ограничения
FK
- Попытка оптимизации Создание других индексов с / без включаемых столбцов
- Идентификация проблемы Изменение запроса для выбора значения как
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