我有简单的表格:
CREATE TABLE dbo.Table1 (
ID int IDENTITY(1,1) PRIMARY KEY,
TextField varchar(100)
)
我在TextField
列上有非聚集索引。
我正在创建一个简单的查询,它会选择两个列以及我在下一个情况下的条件:
...
WHERE SUBSTRING(TextField, 1, 1) = 'x'
使用“x%”将查询转换为LIKE
条件或在TextField
列上创建分区函数是否更好。
分区如何影响varchar列的搜索条件,哪种解决方案对大量行更好?
答案 0 :(得分:2)
默认情况下,SUBSTRING(TextField, 1, 1) = 'x'
不能SARG
。
首先,我将使用以下解决方案测试该查询(SQL Profiler> {SQLStatement | Batch}已完成> CPU,读取,写入,持续时间列):
1) TextField
列上的非聚集索引:
CREATE INDEX IN_Table1_TextField
ON dbo.Table1(TextField)
INCLUDE(non-indexed columns); -- See `SELECT` columns
GO
查询应使用LIKE
:
SELECT ... FROM TextField LIKE 'x%'; -- Where "x" represent one or more chars.
优点/缺点:B-Tree /索引将有多个级别,因为密钥长度(如果不是最大100个字符+ RowID,则是UNIQUE索引)。
2)我会为第一个char创建一个计算列:
-- TextField column needs to be mandatory
ALTER TABLE dbo.Table1
ADD FirstChar AS (CONVERT(CHAR(1),SUBSTRING(TextField,1,1))); -- This computed column could be non-persistent
GO
加
CREATE INDEX IN_Table1_FirstChar
On dbo.Table1(FirstChar)
INCLUDE (non-indexed columns);
GO
在这种情况下,谓词可以是
WHERE SUBSTRING(TextField, 1, 1) = 'x'
或
WHERE FirstChar = 'x'
优点/缺点:B-Tree / index的级别要小得多,因为密钥长度(1个字符+ RowID)。我会使用谓词选择性高(少量行验证)但没有覆盖列(参见INCLUDE
子句)。
3) FirstChar
列上的群集索引因此:
CREATE TABLE dbo.Table1 (
ID int IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
TextField varchar(100) NOT NULL, -- This column needs to be mandatory
ADD FirstChar AS (CONVERT(CHAR(1),SUBSTRING(TextField,1,1))),
UNIQUE CLUSTERED(FirstChar,ID)
);
在这种情况下,谓词可以是
WHERE SUBSTRING(TextField, 1, 1) = 'x'
或
WHERE FirstChar = 'x'
优点/缺点:如果你有很多行,应该给你很好的表现。在这种情况下,B树级别将最小(1 CHAR
+ 1 INT
)或最小 - >中等。
答案 1 :(得分:1)
如果有一个函数应用于列(即SUBSTRING),则无法使用非聚集索引。喜欢'x%'会更好。