在 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 列 col10varchar(20)IS_MEMBER() 接受 sysname 作为参数,因此服务器将您的 varchar(20) 转换为nvarchar(20)sysnamenvarchar(128)

2) How to avoid above warning?

将您的 col10 类型更改为 sysname 或至少更改为 nvarchar(20)