我确实有一个我不明白的问题。
我有两个条件的查询。这个查询非常慢,所以我创建了一个索引。在这之后,我有一种奇怪的行为。
如果我直接使用
... WHERE xxx=1234
将在4毫秒内传递结果
当我使用类似
DECLARE @P1 bigint
SET @P1=1234
...WHERE xxx=@P1
结果将在80k毫秒内交付
我发现了一些有关参数嗅探的信息-并且我将其停用-行为相同。我已使用
将其停用ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SNIFFING = OFF;
当我运行查询时
OPTION (OPTIMIZE FOR (@P1 = 1234))
结果将在4毫秒后再次发送。
我的问题是:我没有机会使用OPTIMIZE FOR,因为SQL语句是因为该查询是由程序查询的。
你们能告诉我如何告诉SQL-Server使用查询计划,就像他没有参数一样吗?
这是该表的创建表:
CREATE TABLE [dbo].[CRM_RO](
[ID] [bigint] NOT NULL,
[ID_FI] [bigint] NOT NULL,
[ID_PE] [bigint] NOT NULL,
[ID_GENERIC] [bigint] NOT NULL,
[DateiKurzk] [nchar](4) NOT NULL,
[RelPosNr] [int] NOT NULL,
[Partnerrolle] [int] NOT NULL,
[KopfExtKey] [nvarchar](20) NULL,
[PosExtKey] [nvarchar](20) NULL,
[Dokument1] [nvarchar](20) NULL,
[Dokument2] [nvarchar](20) NULL,
[SAPAbglStat] [tinyint] NOT NULL,
[SAPAbglDatum_DT] [bigint] NOT NULL,
[SAPAbglModus] [tinyint] NOT NULL,
[FreiK1] [int] NOT NULL,
[FreiK2] [int] NOT NULL,
[FreiK3] [int] NOT NULL,
[FreiK4] [int] NOT NULL,
[FreiK5] [int] NOT NULL,
[FreiC1] [nvarchar](40) NULL,
[FreiC2] [nvarchar](40) NULL,
[FreiC3] [nvarchar](40) NULL,
[FreiC4] [nvarchar](40) NULL,
[FreiC5] [nvarchar](40) NULL,
[FreiN1] [int] NOT NULL,
[FreiN2] [int] NOT NULL,
[FreiN3] [int] NOT NULL,
[FreiN4] [int] NOT NULL,
[FreiN5] [int] NOT NULL,
[FreiD1] [int] NOT NULL,
[FreiD2] [int] NOT NULL,
[FreiD3] [int] NOT NULL,
[FreiD4] [int] NOT NULL,
[FreiD5] [int] NOT NULL,
[FreiL1] [bit] NOT NULL,
[FreiL2] [bit] NOT NULL,
[FreiL3] [bit] NOT NULL,
[FreiL4] [bit] NOT NULL,
[FreiL5] [bit] NOT NULL,
[FreiDez1] [float] NOT NULL,
[FreiDez2] [float] NOT NULL,
[FreiDez3] [float] NOT NULL,
[FreiDez4] [float] NOT NULL,
[FreiDez5] [float] NOT NULL,
[Neu] [bigint] NOT NULL,
[Upd] [bigint] NOT NULL,
[UpdL] [bigint] NOT NULL,
[LosKZ] [bit] NOT NULL,
[AstNr] [int] NOT NULL,
[KomKz] [bit] NOT NULL,
[RKZ] [binary](30) NOT NULL,
[Inaktiv] [bit] NOT NULL,
[DatumVon] [int] NOT NULL,
[DatumBis] [int] NOT NULL,
[UPD_FIELD] [varbinary](334) NULL,
[MNO] [int] NOT NULL,
[F7000] [int] NOT NULL,
[F7002] [int] NOT NULL,
[F7004] [nvarchar](35) NULL,
[F7005] [nvarchar](35) NULL,
[F7006] [nvarchar](35) NULL,
[F7007] [nvarchar](35) NULL,
[F7008] [nvarchar](35) NULL,
[F7009] [int] NOT NULL,
[F7010] [nvarchar](35) NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [ID]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [ID_FI]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [ID_PE]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [ID_GENERIC]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ('') FOR [DateiKurzk]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [RelPosNr]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [Partnerrolle]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [SAPAbglStat]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [SAPAbglDatum_DT]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [SAPAbglModus]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiK1]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiK2]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiK3]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiK4]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiK5]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiN1]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiN2]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiN3]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiN4]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiN5]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiD1]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiD2]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiD3]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiD4]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiD5]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiL1]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiL2]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiL3]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiL4]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiL5]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiDez1]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiDez2]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiDez3]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiDez4]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [FreiDez5]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [Neu]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [Upd]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [UpdL]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [LosKZ]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [AstNr]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [KomKz]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT (0x) FOR [RKZ]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [Inaktiv]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [DatumVon]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [DatumBis]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [MNO]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [F7000]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [F7002]
GO
ALTER TABLE [dbo].[CRM_RO] ADD DEFAULT ((0)) FOR [F7009]
GO
这是CREATE INDEX代码。请不要把net弄糊涂了,它的名称是“ missing index”。这只是因为我使用了语法。我根据ORDER BY编制了索引:
CREATE INDEX [QS_missing_index_583420_583419_CRM_RO] ON [CRM].[dbo].[CRM_RO] (ID_FI,ID_PE,DateiKurzk,ID_GENERIC,RelPosNr,Partnerrolle)
答案 0 :(得分:0)
这是我们在应用程序中使用存储过程而不是实际查询的原因之一。如果像这样需要调整查询,则对存储过程进行更改要比打开应用程序简单得多。
话虽如此,打开应用程序并将查询交换为存储过程确实是最好的答案。调整该查询的唯一其他可能方法是通过查询存储。看看此页面:https://blogs.technet.microsoft.com/dataplatform/2017/01/31/query-store-how-it-works-how-to-use-it/
特别是“ 1)可以比较计划,这在参数嗅探的情况下特别有用”和“ 2)也可以强制执行计划”部分。
答案 1 :(得分:0)
对于参数嗅探,您不必关闭该选项。您可以为参数设置局部变量并使用它们。如果查看执行计划,您将看到SQL Server不再缓存参数值。
我并没有遇到很多问题,但是遇到了这样的情况,例如,查询需要运行<1s并且SSRS报告调用它需要几分钟,并且这样做可以解决问题。因此,如果代码运行很快,但是调用它的却没有,那可能是参数嗅探。
CREATE PROCEDURE dbo.Test ( @var int )
AS
DECLARE
@_var int
SELECT
@_var = @var
SELECT *
FROM dbo.SomeTable
WHERE
Id = @_var
我会尝试一下,看看是否有帮助。
您也可以优化未知,但是我不确定这是否会对您有所帮助。
自创建索引以来,您还可以尝试在联接中添加表提示,以确保SQL Server在其他调用它时使用该索引(例如SELECT * FROM dbo.TableName WITH (INDEX(ix_Index))
)。通常,我会尽量避免这样做。