Pregunta

Estoy trabajando en una tienda electrónica que vende productos únicamente mediante préstamos.Muestro 10 productos por página en cualquier categoría, cada producto tiene 3 etiquetas de precios diferentes: 3 tipos de préstamos diferentes.Todo salió bastante bien durante el tiempo de prueba, el tiempo de ejecución de la consulta fue perfecto, pero hoy, cuando se transfirieron los cambios al servidor de producción, el sitio "colapsó" en aproximadamente 2 minutos.La consulta que se utiliza para seleccionar tipos de préstamos a veces se bloquea durante aproximadamente 10 segundos y sucede con frecuencia, por lo que no puede mantenerse al día y su muy lento.La tabla que se utiliza para almacenar los datos tiene aproximadamente 2 millones de registros y cada selección tiene este aspecto:

SELECT * 
FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND 369.27 BETWEEN CENA_OD AND CENA_DO;

3 tipos de préstamo y el precio que debe estar en el rango entre CENA_OD y CENA_DO, por lo que se devuelven 3 filas.

Pero como necesito mostrar 10 productos por página, necesito ejecutarlo a través de una selección modificada usando O, ya que no encontré ninguna otra solución a esto.he preguntado sobre eso aquí, pero no obtuvo respuesta.Como se menciona en la publicación de referencia, esto debe hacerse por separado ya que hay No columna que podría usarse en una combinación (excepto, por supuesto, el precio y el código, pero terminó muy, muy mal).Aquí está el show create table, kod y CENA_OD/CENA_DO muy indexados vía INDEX.

CREATE TABLE `products_loans` (
  `KOEF_ID` bigint(20) NOT NULL,
  `KOD` varchar(30) NOT NULL,
  `AKONTACIA` int(11) NOT NULL,
  `POCET_SPLATOK` int(11) NOT NULL,
  `koeficient` decimal(10,2) NOT NULL default '0.00',
  `CENA_OD` decimal(10,2) default NULL,
  `CENA_DO` decimal(10,2) default NULL,
  `PREDAJNA_CENA` decimal(10,2) default NULL,
  `AKONTACIA_SUMA` decimal(10,2) default NULL,
  `TYP_VYHODY` varchar(4) default NULL,
  `stage` smallint(6) NOT NULL default '1',
 PRIMARY KEY  (`KOEF_ID`),
 KEY `CENA_OD` (`CENA_OD`),
 KEY `CENA_DO` (`CENA_DO`),
 KEY `KOD` (`KOD`),
 KEY `stage` (`stage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Y además seleccionar todos los tipos de préstamos y luego filtrarlos a través de php no funciona bien, ya que cada tipo tiene más de 50.000 registros y la selección también lleva demasiado tiempo...

Se agradece cualquier idea sobre cómo mejorar la velocidad.

Editar:

Aquí está la explicación.

+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
| id | select_type | table          | type  | possible_keys       | key  | key_len | ref  | rows   | Extra       |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | products_loans | range | CENA_OD,CENA_DO,KOD | KOD  | 92      | NULL | 190158 | Using where |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+

Probé el índice combinado y mejoró el rendimiento en el servidor de prueba de 0,44 segundos a 0,06 segundos. Sin embargo, no puedo acceder al servidor de producción desde casa, así que tendré que probarlo mañana.

¿Fue útil?

Solución

Trate de refactorizar su consulta como:

SELECT * FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND CENA_OD >= 369.27
AND CENA_DO <= 369.27;

(MySQL no es muy inteligente al elegir índices) y comprobar el rendimiento.

El siguiente intento es agregar una llave combinada - (KOD, CENA_OD, CENA_DO)

Y la próxima gran oportunidad es refactorizar su base de tener productos separados de los precios. Esto si realmente ayuda.

PS:. También puede migrar a PostgreSQL, es más inteligente que MySQL hora de elegir los índices correctos

Otros consejos

Su problema es que usted está en busca de intervalos que contienen un punto (en lugar de la consulta más normal de todos los puntos en un intervalo). Estas consultas no funcionan bien con el índice de árbol B estándar, por lo que se necesita hacer uso de un índice de árbol R. Desafortunadamente MySQL no permite seleccionar un índice de árbol R en una columna, pero se puede obtener el índice deseado cambiando el tipo de la columna a la geometría y el uso de las funciones geométricas para comprobar si el intervalo contiene el punto.

Quassnoi 's artículo lista de adyacencia vs. conjuntos anidados: MySQL donde explica esto con más detalle. El caso de uso es diferente, pero las técnicas utilizadas son las mismas. He aquí un extracto de la parte pertinente del artículo:

  

También hay una cierta clase de tareas que requieren buscar todos los intervalos que contienen un valor conocido:

     
      
  • En busca de una dirección IP en la lista de prohibición de rango IP
  •   
  • La búsqueda de una fecha determinada dentro de un intervalo de fechas
  •   
     

y varios otros. Estas tareas se pueden mejorar mediante el uso de las capacidades de R-árbol de MySQL.

MySQL sólo puede utilizar la tecla 1. Si usted consigue siempre la entrada de las 3 columnas, en función de los datos reales (rango) en las columnas uno de los siguientes podría muy bien añadir una cantidad seria de ejecución:

ALTER TABLE products_loans ADD INDEX(KOD, CENA_OD, CENA_DO);
ALTER TABLE products_loans ADD INDEX(CENA_OD, CENA_DO, KOD);

Tenga en cuenta que el orden de las columnas importa! Si esto no mejora el rendimiento, nos dan la salida EXPLAIN de la consulta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top