Кращий підхід для "ПОДОБАЙТЕ АБО ЛІКУЙТЕ


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

Горіхи


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

Ви можете згорнути жетони до цілих чисел, використовуючи enum, або метод ручного прокатування, запропонований sp_BlitzErik, але якщо ви можете зробити згортання, чому ви робите і без закоху? Тобто, якщо ви знаєте, що "% pasta%" - це маркер "pasta", чому у вас є %обидві сторони. Без '%' це перевірка рівності, і це має досить швидко, навіть як текст.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.