当 SQL 中的 LIKE 无法满足要求时,你怎么办?
共 2100字,需浏览 5分钟
·
2020-07-28 16:48
点击蓝色“有关SQL”关注我哟
加个“星标”,天天与10000人一起快乐成长
图 | 榖依米
故事要从我还在工厂写 MIS 软件的时候说起。
那时,公司大大小小的管理软件系统都由信息部门的5个人负责编程。我是其中之一。每个人都有自己的独门编程绝技,也会互相讨论语言的成熟与衰败,就像现在 Java, c#, Python, PHP 一样的笑话,我们那个时候也有。
公司有7,8个分厂,每个分厂原本都是独立的部门,所以信息系统采用的编程语言也都不同。有用 Delphi, VB, c#,还有用 VFP, Java和 ASP.NET. 所以每个分厂提出的需求,只要不是更改数据库,都会路由给不同的队友。
比如那天我就接到一个 ASP.NET 的活儿,工厂要建一个内部网站,除了公布厂子的绩效,个人荣誉之外,还希望员工可以多留言,多提建议。负责布置这个活儿的是工厂的一位党支部书记。
看着这位年近半百的女书记,天天往信息中心跑,雨天也跑,大夏天也跑,就为了一个留言板,我们坐办公室的这些小年轻都挺感动的。不禁感慨,组织中办实事的干部,还是有的。
所以不到一个礼拜,这个网站就出来了。这位女书记每次来看到样品,都一个劲儿的夸我们多么多么能。这种情况下,我们都不好意思拖太久。只是女书记提的一个要求,总是有点小瑕疵。她希望的是,通过搜索组合关键字,比如伙食+食堂,能够看到员工对食堂的饭菜有什么抱怨。但做测试的时候,塞了太多测试数据进去,导致一条 LIKE 的SQL,跑的特别慢,因为伙食+食堂,是一个 OR 的表达式,前一个 LIKE ,后再来一个 LIKE, 大几十万条数据,SQL SERVER 2008 就给跑跪了。
当然,现在大家可能都会笑话这种设计了,为什么用 LIKE 去跑这种全文搜索呢,为什么不用SQL Server 自带的 FullText Search呢。但当时,我们缺少这样的思路。
那怎么办呢,女书记每次来都要提这个事。弄得我们都挺不好意思。于是,给了个折中的办法,异步跑批。女书记每次提交关键词,等待数据库给她跑。一旦出结果,就存储起来,在UI给她刷新处理状态。如果上一次提交的词跑完了,状态就给她个绿色,方便她查看。如果还在跑着,就是红色。
看着女书记满意的走了,我们几个也就开始琢磨,到底有什么方法可以替代 LIKE 呢,一来 LIKE 查询不够灵活,除了 % 的有限魅力之外,处理组合搜索一塌糊涂。二来,速度真是要了亲命。于是在当时谷歌还能用的情况下,我们大概搜索到两种方法,一种是增加 CLR 函数,一种是使用SQL Server 的FullText search, 即全文检索。
CLR函数,可以完美解决 LIKE 的死板,LIKE 在搜索时,除了 %,其实还有模式搜索,比如 %【0-9】%,%【a-z】%, 但是要让 LIKE 实现 123abc345def 的搜索就难了。总不至于写很多【0-9】【a-z】吧。所以要将正则表达放到数据库中来,必须使用CLR函数。使用c#/vb.net就能封装一个正则表达函数,并将它嵌入到 SQL Server 中,充当内部函数使用。
真正让我觉得找到宝藏的是 FullText Search.
这是颠覆索引概念的领域。通常我们所说的数据库索引是这样的树:
除了底层的页面存储了实际的数据页地址,其他索引页都只是指向下一级的索引页。
而全文索引领域,采用的索引,叫做倒排索引 Inverted Index:
经过一系列处理后,最终会形成这样一个列表,记录着所有关键字,记住是所有文档中出现的关键字,对应的文档和在文档中出现的地址。比如 DBA, 在文档1和文档3中出现过,分别是在第10个位置和第50个位置。
这样,搜索关键字 DBA,直接O(1)的速度就查询出相关的文档,这里所说的文档,可以看做二维表中的一行。
与关系型数据库中的索引对比下:
在传统的数据库索引中,“DBA” 在理想状态下,可能要经过2级B树索引的查询,才能最终定位到。假如 DBA 在前面有 ABCDBAE,那么不知道还要经过多少中间层的过滤。
所以B树索引,与倒排索引(inverted index)有着同样怪异的名字,叫做顺排索引(forward index),字面意思,按照大小从前往后排。就像图中所示的DBA关键字一样,如果有2条,就排上两条,如果有20条呢,同样也排上20条,只不过每个指向数据页的指针,或许有些许不同罢了。
现在处理这种文字的全文搜索问题,大家应该都晓得了,用ElasicSearch即可。它所采用的索引,也就是倒排索引。
往期精彩: