ทำไมฉันถึงได้รับการแปลงโดยนัยของ Int / Smallint เป็น Varchar และมันส่งผลกระทบต่อการประเมิน Cardinality จริง ๆ หรือไม่


11

ฉันกำลังพยายามแก้ไขปัญหาแบบสอบถามที่ทำงานช้าโดยใช้ Show Plan Analysis (SSMS) บนแผนปฏิบัติการจริง เครื่องมือวิเคราะห์ชี้ให้เห็นว่าการประมาณการจำนวนแถวนั้นไม่ได้ผลการค้นหาที่ส่งคืนในบางสถานที่ในแผนและให้คำเตือนการแปลงโดยนัยเพิ่มเติม

ฉันไม่เข้าใจการแปลงโดยนัยเหล่านี้ของ int ไปเป็น Varchar- เขตข้อมูลที่อ้างถึงไม่ได้เป็นส่วนหนึ่งของพารามิเตอร์ / ตัวกรองใด ๆ ในแบบสอบถามและในตารางทั้งหมดที่เกี่ยวข้องกับชนิดข้อมูลคอลัมน์จะเหมือนกัน:

ฉันได้รับคำเตือนจาก Cardinality ด้านล่าง:

การแปลงประเภทในนิพจน์ (CONVERT_IMPLICIT (varchar (12), [ccd]. [profileid], 0)) อาจส่งผลต่อ "CardinalityEstimate" ในตัวเลือกแผนแบบสอบถาม - ฟิลด์นี้เป็นจำนวนเต็มทุกที่ในฐานข้อมูลของฉัน

การแปลงประเภทในนิพจน์ (CONVERT_IMPLICIT (varchar (6), [ccd]. [nodeid], 0)) อาจส่งผลต่อ "CardinalityEstimate" ในตัวเลือกแผนแบบสอบถาม - ฟิลด์นี้มีขนาดเล็กทุกที่ใน DB ของฉัน

การแปลงประเภทในการแสดงออก (CONVERT_IMPLICIT (varchar (6), [ccd]. [sessioneqnum], 0)) อาจส่งผลต่อ "CardinalityEstimate" ในตัวเลือกแผนแบบสอบถาม - ฟิลด์นี้มีขนาดเล็กทุกที่ในฐานข้อมูลของฉัน

การแปลงประเภทในนิพจน์ (CONVERT_IMPLICIT (varchar (41), [ccd]. [sessionid], 0)) อาจส่งผลต่อ "CardinalityEstimate" ในตัวเลือกแผนแบบสอบถาม - ฟิลด์นี้เป็นทศนิยมทุกที่ในฐานข้อมูลของฉัน

[แก้ไข] นี่คือข้อความค้นหาและแผนการดำเนินการจริงสำหรับการอ้างอิง https://www.brentozar.com/pastetheplan/?id=SysYt0NzN

และคำจำกัดความของตาราง ..

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

คำตอบ:


11

การแปลงโดยนัยเกิดจากคอลัมน์ที่คำนวณ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,
);

เมื่อพิจารณาจากตารางที่เรียบง่ายด้านบนคำสั่งง่าย ๆ ด้านล่างนี้จะสร้างคำเตือนการแปลงโดยนัยที่เหมือนกันในคำถาม:

SELECT T.*
FROM dbo.Test AS T;

วางแผนด้วยคำเตือน

จากเอกสาร (เน้นเพิ่ม):

CONCAT แปลงอาร์กิวเมนต์ทั้งหมดเป็นชนิดสตริงโดยปริยายก่อนทำการต่อข้อมูล

คำเตือนจะถูกเพิ่มเมื่อ SQL Server พิจารณาทางเลือกแผนที่ไม่ได้ใช้ค่าที่เก็บไว้ แต่คำนวณค่าอย่างชัดเจน คำเตือนจะไม่ถูกลบหากแผนสุดท้ายใช้ค่าคงอยู่

คำเตือนอาจถูกละเว้นอย่างปลอดภัยในกรณีนี้ นอกจากนี้ยังนำไปใช้กับแผนการดำเนินการของคุณเท่าที่ฉันสามารถบอกได้ว่าการแปลงโดยนัยที่เกี่ยวข้องในการCONCATไม่ได้มีผลกระทบต่อการเลือกแผน

การใช้แฟล็กการติดตามที่ไม่มีเอกสารและไม่สนับสนุน 176 ป้องกันการขยายคอลัมน์ที่คำนวณแล้วและลบคำเตือน:

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

กับ TF 176

ดูบทความของฉันคอลัมน์ที่คำนวณอย่างถูกต้องสำหรับรายละเอียดเพิ่มเติม


5

นี่คือฟิลด์ที่คุณได้รับคำเตือนเกี่ยวกับการแปลงโดยนัยเกี่ยวกับ:

  • [ccd].[profileid] (int ถึง varchar (12))
  • [ccd].[nodeid] (smallint to varchar (6))
  • [ccd].[sessionseqnum] (smallint to varchar (6))
  • [ccd].[sessionid] (ทศนิยมเป็น varchar (41))

เขตข้อมูลอ้างอิงไม่ได้เป็นส่วนหนึ่งของพารามิเตอร์ / ตัวกรองใด ๆ ในแบบสอบถาม

แน่นอนว่าพวกเขาอยู่ในเงื่อนไขการเข้าร่วมของคุณ นี่คือตำแหน่งที่จะใช้ ccd.profileid เป็นตัวกรอง (รวมถึงในการเข้าร่วม 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

และในตารางทั้งหมดที่เกี่ยวข้องประเภทข้อมูลคอลัมน์จะเหมือนกัน

คุณอาจต้องการตรวจสอบคำจำกัดความของตารางอีกครั้ง

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

ดูเหมือนว่าพวกเขาไม่ได้ใช้ประเภทข้อมูลที่คุณคิดว่ากำลังใช้งานอยู่

และมันส่งผลกระทบต่อการประมาณการณ์ของ Cardinality จริง ๆ หรือไม่?

มีคำตอบเกิดขึ้นในข้อมูลที่คุณให้ไว้ ฉันขอแนะนำให้คุณเพิ่มแผนปฏิบัติการจริงและคำจำกัดความของตารางในคำถามของคุณเพื่อให้เรามีรายละเอียดทั้งหมดที่เกี่ยวข้องซึ่งอาจนำไปสู่ปัญหาการแปลงโดยนัยเหล่านี้

โดยทั่วไปการแปลงโดยนัยสำหรับเงื่อนไขการเข้าร่วมอาจทำให้เกิดปัญหาร้ายแรงกับการประมาณการ เป็นการยากที่จะบอกว่าสิ่งนี้เกิดขึ้นในกรณีของคุณโดยไม่เห็นแผนการดำเนินการจริง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.