Mejor enfoque para "ME GUSTA O ME GUSTA, O ME GUSTA, O ME GUSTA, O ME GUSTA"


10

En esta pregunta , tiene el mismo problema que yo. Necesito algo como:

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

Esto es feo y no usa índices. En este caso, esta es realmente la única forma de hacer esto (para seleccionar varias palabras dentro de una cadena), ¿o debería usar FULLTEXT?

Según tengo entendido, con texto completo, puedo seleccionar varias palabras dentro de una cadena.

Esta pregunta también habla sobre el texto completo


3
¿Cuál es el tipo de datos de la columna del producto? ¿Cuántos personajes en promedio?
Joe Obbish el

Respuestas:


17

Los índices de texto completo generalmente no son una viñeta mágica y requieren mantenimiento adicional, espacio en disco y cambios bastante intrusivos en los patrones de consulta.

A menos que realmente necesite indexar documentos grandes (piense en cuerpos de correo electrónico, PDF, documentos de Word, etc.), son excesivos (y si somos honestos, eliminaría ese proceso de SQL Server por completo y use Elasticsearch o algo similar).

Para casos de uso más pequeños, las columnas calculadas son generalmente un mejor enfoque.

Aquí hay una configuración de demostración rápida:

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)

Las consultas basadas incluso en una columna no persistente nos dan un plan que 'usa índices' y todo :)

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

NUECES


-3

La respuesta de sp_BlitzErik tiene muchos puntos buenos, pero no creo que sea por eso que no deberías usar la búsqueda de texto completo. La búsqueda de texto completo no está ahí para hacer lo que crees que hace. No está allí para buscar múltiples campos. Está allí para vectorizar el contenido de las palabras y hacer uso de diccionarios, trozos, lexers, diccionarios geográficos, eliminación de palabras vacías y una serie de otros trucos, ninguno de los cuales se aplica. O, aún no se ha demostrado que se apliquen.

Tampoco estoy de acuerdo con la solución, aunque no estoy seguro de cómo hacerlo mejor en SQL Server. Recreemos sus datos para PostgreSQL: también es mucho más limpio crear en 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;

Ahora lo que quieres es un tipo de enumeración,

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

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

Ahora ha colapsado las cadenas a representaciones enteras. Pero aún mejor puedes consultarlos como antes.

SELECT *
FROM fulltextindexesarestupid
WHERE StopAbusingFeatures = 'Bad';

Esto tiene el efecto.

  1. oculta el hecho de que sus categorías son un tipo enumerado. Esa complejidad está encapsulada en el tipo y oculta al usuario.
  2. También coloca el mantenimiento en esas categorías en el tipo.
  3. Está estandarizado.
  4. no aumenta el tamaño de la fila.

Sin estos beneficios, básicamente solo estás tratando de optimizar la comparación de cadenas. Pero, por desgracia, ni siquiera estoy seguro de cómo sp_BlitzErik llega a la respuesta dado el código en la sugerencia,

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

Puede colapsar los tokens a números enteros usando una enumeración, o el método de desplazamiento manual sugerido por sp_BlitzErik, pero si puede hacer el colapso, ¿por qué hace lo mismo sin anclar? Es decir, si sabes que '% pasta%' es el token 'pasta', ¿por qué tienes los %dos lados? Sin '%', esta es una verificación de igualdad y debería ser bastante rápida incluso como texto.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.