我想知道最有效的方法是在SQL服务器中优化数据库模型,以便在开头使用带有通配符的LIKE进行查询。我不是数据库专家,因此欢迎使用索引或其他优化的所有建议。
情况: 我有一个表'产品',其中包含以下列:
ShortNameEN (varchar(50))
ShortNameFR (varchar(50))
ShortNameDE (varchar(50))
ShortNameNL (varchar(50))
LongNameEN (varchar(250))
LongNameFR (varchar(250))
LongNameDE (varchar(250))
LongNameNL (varchar(250))
此表包含300000多条记录。
我需要编写一个select语句来查找包含搜索字符串的记录(仅在ShortNameEN中)。 我的问题是
SELECT *
FROM Products
WHERE ShortNameEN LIKE '%searchstring%'
当然,这个查询非常慢。在ShortNameEN上添加索引将无济于事,因为由于第一个通配符而不会使用它们。
问题1:将ShortNameEN列与表格的其余部分分开是否有意义?我不知道磁盘访问/行大小/页面大小以及这将如何影响性能。也许还有其他与文件系统相关的优化可以提高性能吗?
临时解决方案
我找到了一个创造性的“三元组”解决方案,但对我的模型产生了相当大的影响。为此我创建了第二个表'ProductNameFragments',它引用了我的初始表,并按以下方式分解每个ShortNameEN:
ProductId = 123,ShortNameEN ='PRINTER'
的示例ProductId | NameFragment
123 | PRINTER
123 | RINTER
123 | INTER
123 | NTER
123 | TER
123 | ER
123 | R
Product表上的触发器将同步ProductNameFragments表。
这样我可以加入我的两个表,并在没有初始通配符的情况下进行查询。
SELECT p.*
FROM Product p, ProductNameFragment pnf
WHERE p.Id = pnf.ProductId
AND pnf.NameFragment LIKE '%searchstring%'
首次测试表明,这大大提高了我的搜索查询效果。
问题2:我应该在ProductNameFragment上使用常规索引还是聚簇索引?在更新/删除/插入产品时,这将如何影响性能? 更新一个产品名称时,这可能会导致ProductNameFragments表中的50个删除和50个插入。我可以强制索引只更新一次吗?
最后,由于复杂性,我宁愿不使用'trigram'解决方案。所以任何提示或技巧都非常受欢迎。
提前谢谢
史蒂芬
答案 0 :(得分:2)
如果没有全文搜索,则需要进行完整的索引扫描。关于优化主要通配符扫描性能的唯一想法是使用旧版SQL_ *排序规则而不是Windows排序规则。由于比较规则更简单(尽管不那么健壮),传统的排序规则会减少开销。
我建议在ProductFragment
表ProductID
列上使用聚簇索引来优化产品级操作。或者,ProductID
和NameFragment
自然键上的聚簇主键将优化插入/更新/删除操作并确保数据完整性。
答案 1 :(得分:1)
通常,全文检索(FTS)的主要目的是:
Microsoft SQL Server附带的FTS引擎没有领先的通配符搜索,所以不要打扰。
你提到的解决方案是AFAIK,它是唯一一款能够为领先的通配符提供任何体面性能的解决方案。此外,任何声称具有这种功能的FTS产品都将实现这种非常重要的功能。窗帘背后的算法。
对于您自己的实现,像这样的表将是一个良好的开端:
create table dbo.TextFragments (
TextFragment nvarchar(...) not null, -- Maximum size depends on your data
LanguageId int not null,
EntityId int not null,
RowId bigint not null,
constraint [PK_TextFragments] primary key (TextFragment, LanguageId, EntityId, RowId)
);
我把所有语言放在一个表中;如果没有这个,为您的系统添加新语言会变得相当复杂。当然,您也需要一个语言查找表。
EntityId
字段允许您索引来自不同表的数据。如果您只有一个表并且不打算将其他表编入索引,则可以删除该字段。
RowId
字段将行的标识符存储在与该片段匹配的相应表中。当然,您可以调整数据类型或添加其他列以使其适用于您的系统。
正如其他人所建议的那样,您可能希望使用文本片段的排序规则和大小写来优化搜索。将来,如果/当您的系统存储更多条目(比如100M)时,您可能需要引入分区以将单个部分的大小保持在合理的限制范围内。现在它是花生,所以不要担心,或者任何文件系统问题。
答案 2 :(得分:-1)
我会尝试添加一个带有回文的额外列,并用LIKE'keyword%'或LIKE'droweyk%'替换%keyword%query。这也是一个黑客