Лучший подход для «как или нравится, или нравится, или нравится, или нравится»


10

В этом вопросе у него такая же проблема, как и у меня. Мне нужно что-то вроде:

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

Это ужасно и не использует индексы. В этом случае это действительно единственный способ сделать это (выбрать несколько слов внутри строки), или мне следует использовать FULLTEXT?

Как я понимаю, с полным текстом я могу выделить несколько слов внутри строки.

Этот вопрос также говорит о полном тексте


3
Какой тип данных столбца продукта? Сколько символов в среднем?
Джо Оббиш

Ответы:


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

NUTS


-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;

Теперь, что вы хотите, это тип enum,

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%'

Вы можете свернуть токены до целых чисел, используя enum, или метод ручного прокрутки, предложенный sp_BlitzErik, но если вы можете сделать свертывание, почему вы тоже делаете unanchored-like? То есть, если вы знаете, что «% pasta%» является символом «макароны», почему у вас есть %обе стороны от него? Без «%» это проверка на равенство, и она должна работать довольно быстро даже в виде текста.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.