He leído artículos sobre FORCE
índices, pero ¿cómo puedo forzar a MySQL a IGNORE ALL
indexar?
Lo intenté SELECT * FROM tbl IGNORE INDEX(*)
, pero no tuve éxito.
En cuanto a por qué yo (y otros) necesitamos hacer esto: por ejemplo, necesitaba resumir las estadísticas de los árbitros de la siguiente manera:
SELECT
count(*) as c,
SUBSTRING
(
domain_name,
LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
) as tld
FROM `domains_import`
IGNORE INDEX(domain_name)
GROUP BY tld
ORDER BY c desc
LIMIT 100
... pero siempre tengo que mirar qué índices están definidos o determinar qué índice se usará a través de Explain. Sería muy útil simplemente escribir IGNORE INDEX ALL
y simplemente no importarle.
¿Alguien sabe la sintaxis o un truco? (Decenas de líneas a través de tablas de definición de MySQL realmente no son un atajo).
Agregado de la discusión del chat :
Bechmark:
sin índice = 148.5 segundos
con índice = 180 segundos y aún ejecutándose con el envío de datos La matriz SSD es tan poderosa que casi no le importa el caché de datos ...
Definición de referencia:
CREATE TABLE IF NOT EXISTS `domains_import` (
`domain_id` bigint(20) unsigned NOT NULL,
`domain_name` varchar(253) CHARACTER SET ascii COLLATE ascii_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `domains_import`
ADD PRIMARY KEY (`domain_id`),
ADD UNIQUE KEY `domain_name` (`domain_name`);
ALTER TABLE `domains_import`
MODIFY `domain_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT;
InnoDB, la prueba con índice (sin USE INDEX () o similar) todavía se está ejecutando, 250 segundos, simplemente la maté.
LEFT JOIN
que tenía. `USE INDEX ()` hizo que MySQL escaneara una tabla en una tabla de 20K filas y 1 a 1JOIN
s en lugar de cruzar 500 filas entre dos índices. Obtuve 20 veces más rápido.También podrías insertar
WHERE 1=1
Ypercube me acaba de preguntar
Sí, pero le has dado a MySQL una consulta realmente tonta.
1=1
volvería al índice agrupado. No obstante, todavía hay otra forma, pero requiere ser un poco malicioso para el Optimizador.Esto arrojará cada índice debajo del bus con seguridad porque se verificará el valor de cada fila para
domain_name
mucho. Sidomain_name
está indexado, debe elegir una columna para laWHERE column_name=column_name
que no está indexada en absoluto.Acabo de probar esto en una mesa grande en un servidor de ensayo
No se eligen índices
fuente
WHERE id+0 = id*1
el índice todavía se usará, yUsing where
aparecerá un extra .Suponiendo que tiene estos dos índices:
Entonces no importa lo que haga el optimizador; debe escanear esencialmente una cantidad idéntica de cosas.
Caso 1: realiza un escaneo de tabla (o usa domain_id): escaneará pares (id, nombre), ubicará todos los nombres, realizará la SUBSTRING..LOCATE, GROUP BY y finalmente ORDER BY. El GROUP BY y el ORDER BY probablemente necesitan una tabla tmp y una clasificación de archivos. Comprueba
EXPLAIN SELECT ...
si es así.Caso 2: realiza una exploración de índice (de nombre_dominio): ese índice realmente contiene pares (nombre, id), porque InnoDB pone implícitamente la PK al final de cualquier clave secundaria. El resto del procesamiento es paralelo al caso 1.
Una cosa podría ser diferente: el tamaño de los dos BTrees. Haga
SHOW TABLE STATUS LIKE domains_import
para ver Data_length (para el caso 1) y Index_length (para el caso 2). El BTree más grande será más lento.Otra cosa podría ser diferente: el almacenamiento en caché. ¿Cuál es el valor de
innodb_buffer_pool_size
? ¿Cuánta RAM tienes? ¿Pueden los datos (o índice) estar contenidos dentro de la agrupación de almacenamiento intermedio. (¿O será el 37% debido a que se trata de una exploración de tabla / índice?) Si se ajusta, ejecute la consulta dos veces. La segunda vez será aproximadamente 10 veces más rápido debido a no golpear el disco (almacenamiento en caché).Si se trata de una tarea única, SSD ayudará. Si no es así, y puede almacenar en caché toda la tabla, entonces no ayudará después de cargar buffer_pool.
fuente