我有两个列的巨大表:Id和Title。我是bigint,我可以自由选择Title列的类型:varchar,char,text等等。列标题包含随机文本字符串,如“abcdefg”,“q”,“allyourbasebelongtous”,最多255个字符。
我的任务是通过给定子字符串获取字符串。子串也具有随机长度,可以是字符串的开头,中间或结尾。最明显的执行方式:
SELECT * FROM t LIKE '%abc%'
我不关心INSERT,我只需要做快速选择。我该怎么做才能尽快进行搜索?
我使用MS SQL Server 2008 R2,据我所知,全文搜索将毫无用处。
答案 0 :(得分:13)
如果您不关心存储,那么您可以创建另一个包含部分Title条目的表,从每个子字符串开始(每个普通标题最多255个条目)。
通过这种方式,您可以索引这些子字符串,并且只匹配字符串的开头,应该大大提高性能。
答案 1 :(得分:7)
如果你想使用比Randy的答案更少的空间并且你的数据有相当多的重复,你可以创建一个N-Ary树数据结构,其中每个边是下一个字符并挂起每个字符串并在数据中追踪子字符串它。
您按照第一顺序对节点进行编号。然后,您可以为每个记录创建一个最多255行的表,其中包含记录的Id,以及树中与字符串或尾随子字符串匹配的节点ID。然后,当您进行搜索时,您会找到表示您要搜索的字符串的节点ID(以及所有尾随子字符串)并执行范围搜索。
答案 2 :(得分:4)
听起来你已经排除了所有好的选择。
您已经知道您的查询
SELECT * FROM t WHERE TITLE LIKE '%abc%'
不会使用索引,每次都会进行全表扫描。
如果您确定该字符串位于该字段的开头,则可以执行
SELECT * FROM t WHERE TITLE LIKE 'abc%'
将使用Title上的索引。
您确定全文搜索对您没有帮助吗?
根据您的业务需求,我有时会使用以下逻辑:
LIKE 'abc%'
)进行“开始”,这将使用索引。LIKE '%abc%'
)当然,取决于你需要什么,但我已经在我可以首先展示最简单和最常见的结果的情况下使用它,并且只在必要时转移到更难的查询。
答案 3 :(得分:3)
您可以在表格上添加另一个计算列:titleLength as len(title)PERSISTED。这将存储“标题”列的长度。在此创建一个索引。
另外,添加另一个名为ReverseTitle的计算列作为Reverse(title)PERSISTED。
现在,当有人搜索关键字时,请检查关键字的长度是否与标题长度相同。如果是这样,请执行“=”搜索。如果关键字的长度小于titleLength的长度,则执行LIKE。但首先做一个标题LIKE'abc%',然后做一个reverseTitle LIKE'cba%'。与Brad的方法类似 - 即只在需要时才执行下一个困难查询。
此外,如果80-20规则适用于您的关键字/子字符串(即,如果大部分搜索都在少数关键字上),那么您还可以考虑进行某种缓存。例如:假设您发现许多用户搜索关键字“abc”,并且此关键字搜索返回包含ID 20,22,24,25的记录 - 您可以将其存储在单独的表中并将其编入索引。 现在,当有人搜索新关键字时,首先查看此“缓存”表以查看搜索是否已由较早的用户执行。如果是这样,则无需再在主表中查找。只需从“缓存”表中返回结果。
您还可以将上述内容与SQL Server TextSearch结合使用。 (假设您有正当理由不使用它)。但是,您仍然可以首先使用文本搜索来列出结果集。然后对您的表运行SQL查询,以使用TExt搜索返回的ID作为参数以及您的关键字获得准确的结果。
所有这些显然都假设您必须使用SQL。如果没有,你可以探索像Apache Solr这样的东西。
答案 4 :(得分:0)
创建索引视图在您需要搜索的列上的sql create index中有新功能,并在搜索后使用该视图,这将提供更快的结果。
答案 5 :(得分:0)
答案 6 :(得分:0)
做一件事,在特定列上使用主键&以群集形式对其进行索引。
然后使用任何方法(通配符或=或任何方法)进行搜索,它将以最佳方式搜索,因为该表已经是聚簇形式,因此它知道他可以找到的位置(因为列已经是排序形式)