我的回答是:@DenisReznik 是对的 :)
好的,让我们看看。
我从事条形码和大型目录工作多年,我对这个问题很好奇。
所以我自己做了一些测试。
我已经创建了一个表来存储测试数据:
CREATE TABLE [like_test](
[N] [int] NOT NULL PRIMARY KEY,
[barcode] [varchar](40) NULL
)
我知道条形码有很多种,有些只包含数字,有些还包含字母,还有一些甚至可以很复杂。
假设我们的条形码是一个随机字符串。
我已经用 1000 万条随机字母数字数据记录填充了它:
insert into like_test
select (select count(*) from like_test)+n, REPLACE(convert(varchar(40), NEWID()), '-', '') barcode
from FN_NUMBERS(10000000)
FN_NUMBERS() 只是我在我的数据库中使用的一个函数(一种tally_table)
快速获取记录。
我有 1000 万条这样的记录:
N barcode
1 1C333262C2D74E11B688281636FAF0FB
2 3680E11436FC4CBA826E684C0E96E365
3 7763D29BD09F48C58232C7D33551E6C9
让我们声明一个要搜索的变量:
declare @s varchar(20) = 'D34F15' -- random alfanumeric string
让我们使用 LIKE 进行基本尝试,将结果与:
select * from like_test where barcode like '%'+@s+'%'
在我的工作站上,一次完整的聚集索引扫描需要 24.4 秒。非常慢。
SSMS 建议在条形码列上添加索引:
CREATE NONCLUSTERED INDEX [ix_barcode] ON [like_test] ([barcode]) INCLUDE ([N])
500Mb 的索引,我重试了选择,这次是 24.0 秒用于非聚集索引搜索.. 不到 2% 好,几乎相同的结果。与 SSMS 假设的 75% 相差甚远。在我看来,这个指数真的不值得。也许我的 SSD 三星 840 正在发挥作用..
目前我让索引处于活动状态。
让我们试试 CHARINDEX 解决方案:
select * from like_test where charindex(@s, barcode) > 0
这一次完成需要 23.5 秒,并没有比 LIKE 好多少。
现在让我们检查@DenisReznik 的建议,即使用 Binary Collation 应该加快速度。
select * from like_test
where barcode collate Latin1_General_BIN like '%'+@s+'%' collate Latin1_General_BIN
哇,它似乎工作!只有 4.5 秒,这令人印象深刻!好 5 倍..
那么,CHARINDEX 和 Collation 一起怎么样呢?让我们试试吧:
select * from like_test
where charindex(@s collate Latin1_General_BIN, barcode collate Latin1_General_BIN)>0
难以置信! 2.4 秒,快 10 倍..
好的,到目前为止我已经意识到 CHARINDEX 比 LIKE 更好,并且 Binary Collation 比普通字符串排序更好,所以从现在开始我将只使用 CHARINDEX 和 Collation。
现在,我们还能做些什么来获得更好的结果吗?也许我们可以尝试减少我们很长的字符串..扫描总是扫描..
第一次尝试,使用 SUBSTRING 切割逻辑字符串以虚拟处理 8 个字符的条形码:
select * from like_test
where charindex(
@s collate Latin1_General_BIN,
SUBSTRING(barcode, 12, 8) collate Latin1_General_BIN
)>0
太棒了! 1.8 秒.. 我尝试了SUBSTRING(barcode, 1, 8)(字符串的头部)和SUBSTRING(barcode, 12, 8)(字符串的中间),结果相同。
然后我尝试在物理上减小条形码列的大小,与使用 SUBSTRING() 几乎没有区别
最后我尝试删除条形码列上的索引并重复上述所有测试...
我很惊讶得到几乎相同的结果,几乎没有差异。
索引的性能提高了 3-5%,但如果更新目录,则需要 500Mb 的磁盘空间和维护成本。
当然,对于像 where barcode = @s 这样的直接键查找,使用索引需要 20-50 毫秒,如果没有索引,使用排序语法 where barcode collate Latin1_General_BIN = @s collate Latin1_General_BIN 时我们不能少于 1.1 秒
这很有趣。
我希望这会有所帮助