更好的“喜欢,喜欢,喜欢,喜欢,喜欢”的方法


10

在这个问题上,他和我有同样的问题。我需要类似的东西:

select * from blablabla 
where product 
like '%rock%' or
like '%paper%' or
like '%scisor%' or
like '%car%' or
like '%pasta%' 

这很丑陋,并且没有使用索引。在这种情况下,这实际上是唯一的方法(在字符串中选择多个单词),还是应该使用FULLTEXT?

据我了解,全文可以在字符串中选择多个单词。

这个问题也涉及全文


3
产品列的数据类型是什么?平均多少个字符?
Joe Obbish

Answers:


17

全文索引通常不是魔术,而是需要额​​外的维护,磁盘空间以及对查询模式的相当侵入性的更改。

除非您真正需要索引大型文档(例如电子邮件正文,PDF,Word文档等),否则它们会过大(如果说实话,我会完全从SQL Server中删除该过程,并且使用Elasticsearch或类似的东西)。

对于较小的用例,计算列通常是一种更好的方法。

这是一个快速的演示设置:

use tempdb

CREATE TABLE #fulltextindexesarestupid (Id INT PRIMARY KEY CLUSTERED, StopAbusingFeatures VARCHAR(100))

INSERT #fulltextindexesarestupid (Id)
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY (@@ROWCOUNT))
FROM sys.messages AS m
CROSS JOIN sys.messages AS m2

UPDATE #fulltextindexesarestupid
SET StopAbusingFeatures = CASE WHEN Id % 15 = 0 THEN 'Bad'
                               WHEN Id % 3 = 0 THEN 'Idea'
                               WHEN Id % 5 = 0 THEN 'Jeans'
                               END


ALTER TABLE #fulltextindexesarestupid 
ADD LessBad AS CONVERT(BIT, CASE WHEN StopAbusingFeatures LIKE '%Bad%' THEN 1
                    WHEN StopAbusingFeatures LIKE '%Idea%' THEN 1
                    ELSE 0 END)

CREATE UNIQUE NONCLUSTERED INDEX ix_whatever ON #fulltextindexesarestupid (LessBad, Id)

即使是基于非持久性列的查询,也为我们提供了一个“使用索引”的计划:

SELECT COUNT(*)
FROM #fulltextindexesarestupid AS f
WHERE LessBad = 1

坚果


-3

sp_BlitzErik的答案在很多方面都很有帮助,但是我不认为这就是为什么您不应该使用全文搜索的原因。全文搜索无法满足您的要求。不能搜索多个字段。它在那里可以矢量化单词内容,并使用字典,存根,词法分析器,地名词典,停用词消除功能以及许多其他技巧,这些技巧都不适用。或者,尚未显示适用。

我也不同意该解决方案,尽管我不确定如何在SQL Server中更好地做到这一点。让我们为PostgreSQL重新创建他的数据-在PostgreSQL中创建也要干净得多。

CREATE TABLE fulltextindexesarestupid
AS
  SELECT
    id,
    CASE WHEN Id % 15 = 0 THEN 'Bad'
      WHEN Id % 3 = 0 THEN 'Idea'
      WHEN Id % 5 = 0 THEN 'Jeans'
    END AS StopAbusingFeatures
  FROM generate_series(1,1000000) AS id;

现在您想要的是一个枚举类型,

CREATE TYPE foo AS ENUM ('Bad', 'Idea', 'Jeans');

ALTER TABLE fulltextindexesarestupid
  ALTER StopAbusingFeatures
  SET DATA TYPE foo
  USING StopAbusingFeatures::foo;

现在,您已经将字符串折叠为整数表示形式。但更好的是,您可以像以前一样查询它们。

SELECT *
FROM fulltextindexesarestupid
WHERE StopAbusingFeatures = 'Bad';

这具有效果。

  1. 隐藏了您的类别是枚举类型的事实。这种复杂性封装在类型中,对用户隐藏。
  2. 它还会将维护放在类型上的那些类别上。
  3. 它是标准化的。
  4. 它不会增加行大小。

没有这些好处,您实际上只是在尝试优化字符串比较。但可惜的是,鉴于建议中的代码,我什至不确定sp_BlitzErik如何获得答案,

like '%rock%' or
like '%paper%' or
like '%scisor%' or
like '%car%' or
like '%pasta%'

您可以使用枚举或sp_BlitzErik建议的手动滚动方法将标记折叠为整数,但是如果可以折叠,为什么还要像未锚定的那样折叠?即,如果您知道'%pasta%'是令牌'pasta',那么为什么要%在其两面都使用。如果没有'%',则将执行相等性检查,并且即使是文本也应该很快。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.