在 SQL Server 的 where 子句中使用函数(IS_MEMBER)时的基数估计警告
Cardinality Estimate warning when a function(IS_MEMBER ) is used in where clause in SQLServer
考虑以下场景
测试数据
CREATE TABLE T1 (
COL1 numeric (6, 0) NOT NULL,
COL2 numeric (18, 0) NOT NULL,
COL3 numeric (18, 0) NOT NULL,
COL4 numeric (5, 0) NOT NULL,
COL5 numeric (18, 0) NOT NULL,
COL6 varchar (20) NOT NULL,
COL7 varchar (50) NULL,
COL8 numeric (1, 0) NULL,
COL9 numeric (18, 0) NULL,
COL10 varchar (20) NULL
)
ALTER TABLE T1
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_1', '000002', 0, NULL, 'admin_group')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_2', '000002', 0, NULL, 'admin_group')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_3', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_4', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_5', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_6', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_7', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_8', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_9', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_10', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_11', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_12', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_13', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_14', '000002', 0, NULL, 'LOLCOP2')
场景一:
SELECT T1.* from T1
WHERE IS_MEMBER( COL10)=1
--执行计划警告--
"Type conversion in expression (CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
场景二
SELECT * INTO T3 FROM T1 WHERE COL10 IN ('admin_group')
ALTER TABLE T3
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
UPDATE STATISTICS T3
INSERT INTO T3 SELECT * FROM T1 WHERE COL10 IN ('LOLCOP2','QABrowns','SuperUser')
UPDATE STATISTICS T3
SELECT T3.* from T3
WHERE IS_MEMBER( COL10)=1
--执行计划警告:
"Type conversion in expression (CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
场景三
SELECT * INTO T4 FROM T1 WHERE COL10 IN ('admin_group')
ALTER TABLE T4
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
UPDATE STATISTICS T4
SELECT T4.* from T4
WHERE IS_MEMBER( COL10)=1
执行计划警告--None
INSERT INTO T4 SELECT * FROM T1 WHERE COL10 IN ('LOLCOP2','QABrowns','SuperUser')
UPDATE STATISTICS T4
SELECT T4.* from T4
WHERE IS_MEMBER( COL10)=1
执行计划警告--None
提问:
第一种和第二种情况
SELECT T1.* from T1 WHERE IS_MEMBER( COL10)=1
sql 发出以下警告
"Type conversion in expression (CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
但在第 3 种情况下
SELECT T1.* from T1 WHERE IS_MEMBER( COL10)=1
sql 不给出任何警告。
COL10 的数据类型为 varchar(20)。
服务器排序规则: SQL_Latin1_General_CP1_CI_AS
1) 为什么会出现此警告?
2) 如何避免上述警告?
1) Why does this warning happens?
您的 table 列 col10
是 varchar(20)
但 IS_MEMBER()
接受 sysname
作为参数,因此服务器将您的 varchar(20)
转换为nvarchar(20)
(sysname
是 nvarchar(128)
)
2) How to avoid above warning?
将您的 col10
类型更改为 sysname
或至少更改为 nvarchar(20)
考虑以下场景
测试数据
CREATE TABLE T1 (
COL1 numeric (6, 0) NOT NULL,
COL2 numeric (18, 0) NOT NULL,
COL3 numeric (18, 0) NOT NULL,
COL4 numeric (5, 0) NOT NULL,
COL5 numeric (18, 0) NOT NULL,
COL6 varchar (20) NOT NULL,
COL7 varchar (50) NULL,
COL8 numeric (1, 0) NULL,
COL9 numeric (18, 0) NULL,
COL10 varchar (20) NULL
)
ALTER TABLE T1
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_1', '000002', 0, NULL, 'admin_group')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_2', '000002', 0, NULL, 'admin_group')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_3', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_4', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_5', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_6', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_7', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_8', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_9', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_10', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_11', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_12', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_13', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_14', '000002', 0, NULL, 'LOLCOP2')
场景一:
SELECT T1.* from T1
WHERE IS_MEMBER( COL10)=1
--执行计划警告--
"Type conversion in expression
(CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
场景二
SELECT * INTO T3 FROM T1 WHERE COL10 IN ('admin_group')
ALTER TABLE T3
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
UPDATE STATISTICS T3
INSERT INTO T3 SELECT * FROM T1 WHERE COL10 IN ('LOLCOP2','QABrowns','SuperUser')
UPDATE STATISTICS T3
SELECT T3.* from T3
WHERE IS_MEMBER( COL10)=1
--执行计划警告:
"Type conversion in expression (CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
场景三
SELECT * INTO T4 FROM T1 WHERE COL10 IN ('admin_group')
ALTER TABLE T4
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
UPDATE STATISTICS T4
SELECT T4.* from T4
WHERE IS_MEMBER( COL10)=1
执行计划警告--None
INSERT INTO T4 SELECT * FROM T1 WHERE COL10 IN ('LOLCOP2','QABrowns','SuperUser')
UPDATE STATISTICS T4
SELECT T4.* from T4
WHERE IS_MEMBER( COL10)=1
执行计划警告--None
提问:
第一种和第二种情况
SELECT T1.* from T1 WHERE IS_MEMBER( COL10)=1
sql 发出以下警告
"Type conversion in expression (CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
但在第 3 种情况下
SELECT T1.* from T1 WHERE IS_MEMBER( COL10)=1
sql 不给出任何警告。
COL10 的数据类型为 varchar(20)。
服务器排序规则: SQL_Latin1_General_CP1_CI_AS
1) 为什么会出现此警告?
2) 如何避免上述警告?
1) Why does this warning happens?
您的 table 列 col10
是 varchar(20)
但 IS_MEMBER()
接受 sysname
作为参数,因此服务器将您的 varchar(20)
转换为nvarchar(20)
(sysname
是 nvarchar(128)
)
2) How to avoid above warning?
将您的 col10
类型更改为 sysname
或至少更改为 nvarchar(20)