leer - mysql workbench blob
Búsqueda contra la columna de tipo MYSQL TEXT (4)
Mi tabla / modelo tiene una columna de tipo TEXT
, y al filtrar los registros en el propio modelo, el AR where
produce el SQL correcto y devuelve los resultados correctos, esto es lo que quiero decir:
MyNamespace::MyValue.where(value: ''Good Quality'')
Produce este SQL:
SELECT `my_namespace_my_values`.*
FROM `my_namespace_my_values`
WHERE `my_namespace_my_values`.`value` = ''///"Good Quality///"''
Tome otro ejemplo donde me estoy uniendo a MyNamespace::MyValue
y filtrando en la misma columna de value
pero desde el otro modelo (tiene relación en el modelo con my_values
). Vea esto ( consulta # 2 ):
OtherModel.joins(:my_values).where(my_values: { value: ''Good Quality'' })
Esto no produce una consulta correcta, esto filtra en la columna de value
como si fuera una columna de Cadena y no Texto, por lo tanto produce resultados incorrectos como eso (solo pegando relevante donde):
WHERE my_namespace_my_values`.`value` = ''Good Quality''
Ahora puedo superar esto haciendo LIKE dentro de mi AR where
, lo que producirá el resultado correcto pero una consulta ligeramente diferente. Esto es lo que quiero decir :
OtherModel.joins(:my_values).where(''my_values.value LIKE ?, ''%Good Quality%'')
Finalmente llegando a mis preguntas. ¿Qué es esto y cómo se genera en qué parte del modelo (para el tipo de columna de texto)?
WHERE `my_namespace_my_values`.`value` = ''///"Good Quality///"''
Quizás la pregunta más importante es cuál es la diferencia en términos de rendimiento utilizando :
WHERE `my_namespace_my_values`.`value` = ''///"Good Quality///"''
y esto :
(my_namespace_my_values.value LIKE ''%Good Quality%'')
y lo que es más importante, ¿cómo obtengo mi consulta con uniones (consulta n. ° 2) ?
WHERE `my_namespace_my_values`.`value` = ''///"Good Quality///"''
¿Qué es esto y cómo se genera en qué parte del modelo (para el tipo de columna de texto)?
Eso se genera detrás del motor léxico Active Records (Arel). Vea mi respuesta a continuación en su segunda pregunta sobre por qué.
¿Cuál es la diferencia en términos de rendimiento utilizando ...
El "=" coincide con la comparación de cadena / fragmento completo Mientras que LIKE coincide con el (los) carácter (es) (por carácter (es)).
En mis proyectos obtuve tablas con millones de filas, desde mi experiencia es realmente más rápido hasta el uso de ese comparador "=" o regexp que el uso de un LIKE en una consulta.
¿Cómo obtengo mi consulta con uniones (consulta n. ° 2) donde se produce de esta manera ...
¿Puedes probar esto,
OtherModel.joins(:my_values).where(OtherModel[:value].eq(''///"Good Quality///"''))
(Respuesta parcial - acercándose desde el lado de MySQL).
Lo que va a coincidir
Caso 1: (No sé de dónde vienen las barras invertidas y las citas adicionales).
WHERE `my_namespace_my_values`.`value` = ''///"Good Quality///"''
/"Good Quality/" -- matches
Good Quality -- does not match
The product has Good Quality. -- does not match
Caso 2: (Encuentra Good Quality
en cualquier lugar en value
)
WHERE my_namespace_my_values.value LIKE ''%Good Quality%''
/"Good Quality/" -- matches
Good Quality -- matches
The product has Good Quality. -- matches
Caso 3:
WHERE `my_namespace_my_values`.`value` = ''Good Quality''
/"Good Quality/" -- does not match
Good Quality -- matches
The product has Good Quality. -- does not match
Actuación:
- Si el
value
se declaraTEXT
, todos los casos son lentos. - Si el
value
no está indexado, todos son lentos. - Si el
value
esVARCHAR(255)
(o menor) e indexado, los casos 1 y 3 son más rápidos. Puede encontrar rápidamente una fila, en lugar de verificar todas las filas.
Fraseado de manera diferente:
-
LIKE
con un comodín inicial (%
) es lento. - La indexación de la columna es importante para el rendimiento, pero
TEXT
no se puede indexar.
Creo que podría ser útil.
para buscar / n, especifíquelo como / n. Para buscar /, especifíquelo como // esto se debe a que las barras diagonales inversas se eliminan una vez por el analizador y, una vez más, cuando se realiza la coincidencia del patrón, dejando una única barra diagonal inversa.
LIKE y = son diferentes operadores.
= es un operador de comparación que opera con números y cadenas. Cuando se comparan cadenas, el operador de comparación compara cadenas completas.
LIKE es un operador de cadena que compara carácter por carácter.
mysql> SELECT ''ä'' LIKE ''ae'' COLLATE latin1_german2_ci;
+-----------------------------------------+
| ''ä'' LIKE ''ae'' COLLATE latin1_german2_ci |
+-----------------------------------------+
| 0 |
+-----------------------------------------+
mysql> SELECT ''ä'' = ''ae'' COLLATE latin1_german2_ci;
+--------------------------------------+
| ''ä'' = ''ae'' COLLATE latin1_german2_ci |
+--------------------------------------+
| 1 |
+--------------------------------------+
La opción ''='' está buscando una coincidencia exacta, mientras que la operación LIKE está funcionando más como una coincidencia de patrón con ''%'' siendo similar a ''*'' en expresiones regulares.
Así que si tienes entradas con
- Buena calidad
- Más buena calidad
Solo LIKE obtendrá ambos resultados.
Con respecto a la cadena de escape, no estoy seguro de dónde se genera esto, pero parece un escape estandarizado para obtener esto válido para SQL.