Mengapa saya mendapatkan konversi implisit dari Int / Smallint ke Varchar, dan apakah itu benar-benar memengaruhi Perkiraan Kardinalitas?

11

Saya mencoba memecahkan masalah dalam menjalankan permintaan yang lambat menggunakan Show Plan Analysis (SSMS) pada rencana eksekusi yang sebenarnya. Alat Analisis menunjukkan bahwa perkiraan jumlah baris tidak aktif dari hasil yang dikembalikan di beberapa tempat dalam rencana dan selanjutnya memberi saya beberapa peringatan konversi implisit.

Saya tidak mengerti konversi implisit ini int ke Varchar- Bidang yang direferensikan bukan bagian dari parameter / filter pada permintaan dan di semua tabel yang terlibat jenis data kolom adalah sama:

Saya mendapatkan di bawah ini Peringatan Kardinalitas:

Ketik konversi dalam ekspresi (CONVERT_IMPLICIT (varchar (12), [ccd]. [Profileid], 0)) dapat memengaruhi "CardinalityEstimate" dalam pilihan rencana kueri - Bidang ini adalah bilangan bulat di mana saja di DB saya

Ketik konversi dalam ekspresi (CONVERT_IMPLICIT (varchar (6), [ccd]. [Nodeid], 0)) dapat memengaruhi "CardinalityEstimate" dalam pilihan rencana kueri - Bidang ini kecil di mana-mana di DB saya

Ketik konversi dalam ekspresi (CONVERT_IMPLICIT (varchar (6), [ccd]. [Sessioneqnum], 0)) dapat memengaruhi "CardinalityEstimate" dalam pilihan rencana kueri - Bidang ini adalah sebuah titik kecil di mana-mana di DB saya

Ketik konversi dalam ekspresi (CONVERT_IMPLICIT (varchar (41), [ccd]. [Sessionid], 0)) dapat memengaruhi "CardinalityEstimate" dalam pilihan rencana kueri - Bidang ini adalah desimal di mana-mana di DB saya

[EDIT] Berikut ini adalah kueri dan rencana eksekusi aktual untuk referensi https://www.brentozar.com/pastetheplan/?id=SysYt0NzN

Dan definisi tabel ..

/****** 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
sumber

Jawaban:

11

Konversi tersirat disebabkan oleh kolom yang dihitung 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,
);

Dengan tabel sederhana di atas, pernyataan sederhana di bawah ini menghasilkan peringatan konversi implisit yang sama dengan yang diberikan dalam pertanyaan:

SELECT T.*
FROM dbo.Test AS T;

Rencanakan dengan peringatan

Dari dokumentasi (penekanan ditambahkan):

CONCAT secara implisit mengubah semua argumen menjadi tipe string sebelum concatenation.

Peringatan ditambahkan ketika SQL Server mempertimbangkan alternatif rencana yang tidak menggunakan nilai tetap, tetapi menghitung nilai secara eksplisit. Peringatan tidak dihapus jika rencana akhir menggunakan nilai tetap.

Peringatan mungkin diabaikan dengan aman dalam kasus ini. Ini juga berlaku untuk rencana eksekusi Anda, sejauh yang saya tahu - konversi implisit yang terlibat dalam CONCATtidak mempengaruhi pilihan rencana.

Menggunakan flag jejak yang tidak terdokumentasi dan tidak didukung 176 mencegah perluasan kolom yang dihitung terus-menerus dan menghilangkan peringatan:

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

dengan tf 176

Lihat artikel saya Kolom Terhitung yang Ditahan dengan Benar untuk lebih detail

Paul White 9
sumber
5

Ini adalah bidang yang Anda dapatkan tentang peringatan konversi implisit tentang:

  • [ccd].[profileid] (int to varchar (12))
  • [ccd].[nodeid] (smallint to varchar (6))
  • [ccd].[sessionseqnum] (smallint to varchar (6))
  • [ccd].[sessionid] (desimal ke varchar (41))

Bidang yang dirujuk bukan bagian dari parameter / filter apa pun pada kueri

Tentu saja, dalam kondisi bergabung Anda. Di sinilah ccd.profileid digunakan sebagai filter (dan juga dalam join to 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

dan di semua tabel yang terlibat tipe data kolom adalah sama

Anda mungkin ingin memeriksa definisi tabel untuk

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

Sepertinya mereka tidak menggunakan tipe data yang Anda pikir mereka gunakan.

dan apakah itu benar-benar memengaruhi Perkiraan Kardinalitas?

Ada beberapa dugaan yang terjadi dalam jawaban saya berdasarkan informasi yang Anda berikan. Saya mendorong Anda untuk menambahkan rencana eksekusi dan definisi tabel aktual ke pertanyaan Anda sehingga kami memiliki semua detail yang terlibat yang mungkin berperan dalam masalah konversi implisit ini.

Secara umum, konversi implisit pada kondisi bergabung dapat menyebabkan masalah serius dengan perkiraan. Sulit untuk mengatakan apakah ini terjadi dalam kasus Anda tanpa melihat rencana eksekusi yang sebenarnya.

Josh Darnell
sumber