Warum erhalte ich eine implizite Konvertierung von Int / Smallint in Varchar und wirkt sich dies wirklich auf die Kardinalitätsschätzungen aus?

11

Ich versuche, eine langsame Abfrage mithilfe von Show Plan Analysis (SSMS) für den tatsächlichen Ausführungsplan zu beheben. Das Analysetool weist darauf hin, dass Schätzungen für die Anzahl der Zeilen an einigen Stellen im Plan von den zurückgegebenen Ergebnissen abweichen, und gibt mir außerdem einige implizite Konvertierungswarnungen.

Ich verstehe diese impliziten Konvertierungen von int in Varchar nicht. Die Felder, auf die verwiesen wird, sind nicht Teil eines Parameters / Filters in der Abfrage, und in allen beteiligten Tabellen sind die Spaltendatentypen gleich:

Ich erhalte die folgenden Kardinalitätsschätzungen:

Die Typkonvertierung im Ausdruck (CONVERT_IMPLICIT (varchar (12), [ccd]. [Profileid], 0)) kann sich auf "CardinalityEstimate" bei der Auswahl des Abfrageplans auswirken. Dieses Feld ist überall in meiner Datenbank eine Ganzzahl

Die Typkonvertierung im Ausdruck (CONVERT_IMPLICIT (varchar (6), [ccd]. [Nodeid], 0)) kann sich bei der Auswahl des Abfrageplans auf "CardinalityEstimate" auswirken. Dieses Feld ist überall in meiner Datenbank eine Kleinigkeit

Die Typkonvertierung im Ausdruck (CONVERT_IMPLICIT (varchar (6), [ccd]. [Sessionseqnum], 0)) kann sich bei der Auswahl des Abfrageplans auf "CardinalityEstimate" auswirken. Dieses Feld ist überall in meiner Datenbank eine Kleinigkeit

Die Typkonvertierung im Ausdruck (CONVERT_IMPLICIT (varchar (41), [ccd]. [Sessionid], 0)) kann sich auf "CardinalityEstimate" bei der Auswahl des Abfrageplans auswirken. Dieses Feld ist überall in meiner Datenbank eine Dezimalzahl

[EDIT] Hier ist die Abfrage und der tatsächliche Ausführungsplan als Referenz https://www.brentozar.com/pastetheplan/?id=SysYt0NzN

Und Tabellendefinitionen ..

/****** Object:  Table [dbo].[agentconnectiondetail]    Script Date: 1/10/2019 9:10:04 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[agentconnectiondetail](
    [sessionid] [decimal](18, 0) NOT NULL,
    [sessionseqnum] [smallint] NOT NULL,
    [nodeid] [smallint] NOT NULL,
    [profileid] [int] NOT NULL,
    [resourceid] [int] NOT NULL,
    [startdatetime] [datetime2](7) NOT NULL,
    [enddatetime] [datetime2](7) NOT NULL,
    [qindex] [smallint] NOT NULL,
    [gmtoffset] [smallint] NOT NULL,
    [ringtime] [smallint] NULL,
    [talktime] [smallint] NULL,
    [holdtime] [smallint] NULL,
    [worktime] [smallint] NULL,
    [callwrapupdata] [varchar](40) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [callresult] [smallint] NULL,
    [dialinglistid] [int] NULL,
    [convertedStartDatetimelocal] [datetime2](7) NULL,
    [convertedEndDatetimelocal] [datetime2](7) NULL,
 CONSTRAINT [PK_agentconnectiondetail] PRIMARY KEY CLUSTERED 
(
    [sessionid] ASC,
    [sessionseqnum] ASC,
    [nodeid] ASC,
    [profileid] ASC,
    [resourceid] ASC,
    [startdatetime] ASC,
    [qindex] 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
/****** Object:  Table [dbo].[contactcalldetail]    Script Date: 1/10/2019 9:10:04 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[contactcalldetail](
    [sessionid] [decimal](18, 0) NOT NULL,
    [sessionseqnum] [smallint] NOT NULL,
    [nodeid] [smallint] NOT NULL,
    [profileid] [int] NOT NULL,
    [contacttype] [smallint] NOT NULL,
    [contactTypeDescription] [varchar](20) COLLATE Latin1_General_CI_AS NULL,
    [contactdisposition] [smallint] NOT NULL,
    [contactdispositionDescription] [varchar](20) COLLATE Latin1_General_CI_AS NULL,
    [dispositionreason] [varchar](100) COLLATE Latin1_General_CI_AS NULL,
    [originatortype] [smallint] NOT NULL,
    [originatorTypeDescription] [varchar](20) COLLATE Latin1_General_CI_AS NULL,
    [originatorid] [int] NULL,
    [originatordn] [varchar](30) COLLATE Latin1_General_CI_AS NULL,
    [destinationtype] [smallint] NULL,
    [destinationTypeDescription] [varchar](20) COLLATE Latin1_General_CI_AS NULL,
    [destinationid] [int] NULL,
    [destinationdn] [varchar](30) COLLATE Latin1_General_CI_AS NULL,
    [startdatetimeUTC] [datetime2](7) NOT NULL,
    [enddatetimeUTC] [datetime2](7) NOT NULL,
    [gmtoffset] [smallint] NOT NULL,
    [callednumber] [varchar](30) COLLATE Latin1_General_CI_AS NULL,
    [origcallednumber] [varchar](30) COLLATE Latin1_General_CI_AS NULL,
    [applicationtaskid] [decimal](18, 0) NULL,
    [applicationid] [int] NULL,
    [applicationname] [varchar](30) COLLATE Latin1_General_CI_AS NULL,
    [connecttime] [smallint] NULL,
    [customvariable1] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable2] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable3] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable4] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable5] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable6] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable7] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable8] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable9] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [customvariable10] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [accountnumber] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [callerentereddigits] [varchar](40) COLLATE Latin1_General_CI_AS NULL,
    [badcalltag] [char](1) COLLATE Latin1_General_CI_AS NULL,
    [transfer] [bit] NULL,
    [NextSeqNum] [smallint] NULL,
    [redirect] [bit] NULL,
    [conference] [bit] NULL,
    [flowout] [bit] NULL,
    [metservicelevel] [bit] NULL,
    [campaignid] [int] NULL,
    [origprotocolcallref] [varchar](32) COLLATE Latin1_General_CI_AS NULL,
    [destprotocolcallref] [varchar](32) COLLATE Latin1_General_CI_AS NULL,
    [convertedStartDatetimelocal] [datetime2](7) NULL,
    [convertedEndDatetimelocal] [datetime2](7) NULL,
    [AltKey]  AS (concat([sessionid],[sessionseqnum],[nodeid],[profileid]) collate database_default) PERSISTED NOT NULL,
    [PrvSeqNum] [smallint] NULL,
 CONSTRAINT [PK_contactcalldetail] PRIMARY KEY CLUSTERED 
(
    [sessionid] ASC,
    [sessionseqnum] ASC,
    [nodeid] ASC,
    [profileid] 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
/****** Object:  Table [dbo].[contactqueuedetail]    Script Date: 1/10/2019 9:10:04 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[contactqueuedetail](
    [sessionid] [decimal](18, 0) NOT NULL,
    [sessionseqnum] [smallint] NOT NULL,
    [profileid] [int] NOT NULL,
    [nodeid] [smallint] NOT NULL,
    [targetid] [int] NOT NULL,
    [targettype] [smallint] NOT NULL,
    [targetTypeDescription] [varchar](10) COLLATE Latin1_General_CI_AS NULL,
    [qindex] [smallint] NOT NULL,
    [queueorder] [smallint] NOT NULL,
    [disposition] [smallint] NULL,
    [dispositionDescription] [varchar](50) COLLATE Latin1_General_CI_AS NULL,
    [metservicelevel] [bit] NULL,
    [queuetime] [smallint] NULL,
 CONSTRAINT [PK_contactqueuedetail] PRIMARY KEY CLUSTERED 
(
    [sessionid] ASC,
    [sessionseqnum] ASC,
    [profileid] ASC,
    [nodeid] ASC,
    [targetid] ASC,
    [targettype] ASC,
    [qindex] 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
/****** Object:  Index [<Name of Missing Index, sysname,>]    Script Date: 1/10/2019 9:10:04 AM ******/
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>] ON [dbo].[contactcalldetail]
(
    [convertedStartDatetimelocal] ASC
)
INCLUDE (   [sessionid],
    [sessionseqnum],
    [nodeid],
    [profileid]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
/****** Object:  Index [idx_CCD_ContactType_DestType_StDtLocal]    Script Date: 1/10/2019 9:10:04 AM ******/
CREATE NONCLUSTERED INDEX [idx_CCD_ContactType_DestType_StDtLocal] ON [dbo].[contactcalldetail]
(
    [destinationtype] ASC,
    [contacttype] ASC,
    [convertedStartDatetimelocal] ASC
)
INCLUDE (   [sessionid],
    [sessionseqnum],
    [nodeid],
    [profileid],
    [convertedEndDatetimelocal]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object:  Index [idx_CQD_Profile_Traget_TargetType]    Script Date: 1/10/2019 9:10:04 AM ******/
CREATE NONCLUSTERED INDEX [idx_CQD_Profile_Traget_TargetType] ON [dbo].[contactqueuedetail]
(
    [profileid] ASC,
    [targetid] ASC,
    [targettype] ASC
)
INCLUDE (   [targetTypeDescription],
    [queueorder],
    [disposition],
    [dispositionDescription],
    [queuetime]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Voysinmyhead
quelle

Antworten:

11

Die impliziten Konvertierungen werden durch die berechnete Spalte verursacht AltKey:

CREATE TABLE dbo.Test
(
    [sessionid] [decimal](18, 0) NOT NULL,
    [sessionseqnum] [smallint] NOT NULL,
    [nodeid] [smallint] NOT NULL,
    [profileid] [int] NOT NULL,
    [AltKey] AS 
        CONCAT
        (
            [sessionid],
            [sessionseqnum],
            [nodeid],
            [profileid]
        ) PERSISTED NOT NULL,
);

In Anbetracht der obigen vereinfachten Tabelle generiert die folgende einfache Anweisung dieselben impliziten Konvertierungswarnungen, die in der Frage angegeben sind:

SELECT T.*
FROM dbo.Test AS T;

Planen Sie mit Warnungen

Aus der Dokumentation (Hervorhebung hinzugefügt):

CONCAT Konvertiert implizit alle Argumente vor der Verkettung in Zeichenfolgentypen.

Die Warnung wird hinzugefügt, wenn SQL Server eine Planalternative in Betracht zieht, die den persistierten Wert nicht verwendet, den Wert jedoch explizit berechnet. Die Warnung wird nicht entfernt, wenn der endgültige Plan den beibehaltenen Wert verwendet.

Die Warnungen können in diesem Fall ignoriert werden. Dies gilt meines Erachtens auch für Ihren Ausführungsplan - die impliziten Konvertierungen, die mit dem CONCATPlan verbunden sind, wirken sich nicht nachteilig auf die Planauswahl aus.

Die Verwendung eines nicht dokumentierten und nicht unterstützten Ablaufverfolgungsflags 176 verhindert die dauerhafte Erweiterung der berechneten Spalte und entfernt die Warnungen:

SELECT * 
FROM dbo.Test AS T
OPTION (QUERYTRACEON 176);

mit tf 176

Weitere Informationen finden Sie in meinem Artikel Richtig persistierte berechnete Spalten .

Paul White 9
quelle
5

In diesen Feldern erhalten Sie implizite Konvertierungswarnungen:

  • [ccd].[profileid] (int zu varchar (12))
  • [ccd].[nodeid] (smallint zu varchar (6))
  • [ccd].[sessionseqnum] (smallint zu varchar (6))
  • [ccd].[sessionid] (dezimal zu varchar (41))

Die Felder, auf die verwiesen wird, sind nicht Teil eines Parameters / Filters in der Abfrage

Sicher sind sie in Ihren Beitrittsbedingungen. Hier wird ccd.profileid als Filter verwendet (sowie in einem Join zu agentconnectiondetail):

FROM contactcalldetail ccd 
    INNER JOIN contactqueuedetail csqd 
        ON ccd.sessionID=csqd.sessionid 
            AND ccd.sessionSeqNum=csqd.sessionSeqNum 
            AND ccd.nodeID=csqd.nodeID 
            AND ccd.profileid=csqd.profileid -- Right here

und in allen beteiligten Tabellen sind die Spaltendatentypen gleich

Möglicherweise möchten Sie die Tabellendefinitionen für überprüfen

  • contactcalldetail.profileid
  • contactqueuedetail.profileid
  • agentconnectiondetail .profileid

Es hört sich so an, als würden sie nicht die Datentypen verwenden, von denen Sie glauben, dass sie sie verwenden.

und wirkt es sich wirklich auf die Kardinalitätsschätzungen aus?

In meiner Antwort gibt es einige Vermutungen, die auf den von Ihnen angegebenen Informationen beruhen. Ich empfehle Ihnen, Ihrer Frage den eigentlichen Ausführungsplan und die Tabellendefinitionen hinzuzufügen, damit wir alle Details haben, die bei diesen impliziten Konvertierungsproblemen eine Rolle spielen könnten.

Im Allgemeinen kann die implizite Konvertierung unter Join-Bedingungen schwerwiegende Probleme mit Schätzungen verursachen. Es ist schwer zu sagen, ob dies in Ihrem Fall geschieht, ohne den tatsächlichen Ausführungsplan zu sehen.

Josh Darnell
quelle