Tenemos dos tablas se asemeja a una estructura simple etiqueta a grabar la siguiente manera (en realidad es mucho más compleja, pero esta es la esencia del problema):MySQL no usar índice con JOIN, WHERE y ORDER
tag (A.a) | recordId (A.b)
1 | 1
2 | 1
2 | 2
3 | 2
....
y
recordId (B.b) | recordData (B.c)
1 | 123
2 | 666
3 | 1246
El problema es obtener registros ordenados con una etiqueta específica. La manera obvia de hacerlo es con una combinación sencilla e índices en (PK) (Aa, Ab), (Ab), (PK) (Bb), (Bb, Bc) como tal:
select A.a, A.b, B.c from A join B on A.b = B.b where a = 44 order by c;
Sin embargo , esto da el resultado desagradable de un filesort:
+----+-------------+-------+------+---------------+---------+---------+-----------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------+---------+-----------+------+----------------------------------------------+
| 1 | SIMPLE | A | ref | PRIMARY,b | PRIMARY | 4 | const | 94 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | B | ref | PRIMARY,b | b | 4 | booli.A.b | 1 | Using index |
+----+-------------+-------+------+---------------+---------+---------+-----------+------+----------------------------------------------+
Usando una "vista materializada" enorme y muy redundante, podemos obtener un rendimiento bastante bueno, pero esto a costa de complicar la lógica de negocio, algo que le gustaría evite, especialmente porque las tablas A y B ya son MV: s (y son necesarias para otras consultas, y de hecho las mismas consultas usan UNION).
create temporary table C engine=innodb as (select A.a, A.b, B.c from A join B on A.b = B.b);
explain select a, b, c from C where a = 44 order by c;
Para complicar aún más la situación es el hecho de que tenemos los condicionales en la tabla B-rango, tales como filtros.
select A.a, A.b, B.c from A join B on A.b = B.b where a = 44 AND B.c > 678 order by c;
Pero estamos seguros de que podemos manejar esto si el problema del archivador desaparece.
¿Alguien sabe por qué la unión simple en el bloque de código 3 anterior no usará el índice para la clasificación y si podemos resolver el problema de alguna manera sin crear un nuevo MV?
A continuación se muestra la lista completa de SQL que estamos utilizando para la prueba.
DROP TABLE IF EXISTS A;
DROP TABLE IF EXISTS B;
DROP TABLE IF EXISTS C;
CREATE TEMPORARY TABLE A (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY(a, b), INDEX idx_A_b (b)) ENGINE=INNODB;
CREATE TEMPORARY TABLE B (b INT NOT NULL, c INT NOT NULL, d VARCHAR(5000) NOT NULL DEFAULT '', PRIMARY KEY(b), INDEX idx_B_c (c), INDEX idx_B_b (b, c)) ENGINE=INNODB;
DELIMITER $$
CREATE PROCEDURE prc_filler(cnt INT)
BEGIN
DECLARE _cnt INT;
SET _cnt = 1;
WHILE _cnt <= cnt DO
INSERT IGNORE INTO A SELECT RAND()*100, RAND()*10000;
INSERT IGNORE INTO B SELECT RAND()*10000, RAND()*1000, '';
SET _cnt = _cnt + 1;
END WHILE;
END
$$
DELIMITER ;
START TRANSACTION;
CALL prc_filler(100000);
COMMIT;
DROP PROCEDURE prc_filler;
CREATE TEMPORARY TABLE C ENGINE=INNODB AS (SELECT A.a, A.b, B.c FROM A JOIN B ON A.b = B.b);
ALTER TABLE C ADD (PRIMARY KEY(a, b), INDEX idx_C_a_c (a, c));
EXPLAIN EXTENDED SELECT A.a, A.b, B.c FROM A JOIN B ON A.b = B.b WHERE A.a = 44;
EXPLAIN EXTENDED SELECT A.a, A.b, B.c FROM A JOIN B ON A.b = B.b WHERE 1 ORDER BY B.c;
EXPLAIN EXTENDED SELECT A.a, A.b, B.c FROM A JOIN B ON A.b = B.b where A.a = 44 ORDER BY B.c;
EXPLAIN EXTENDED SELECT a, b, c FROM C WHERE a = 44 ORDER BY c;
-- Added after Quassnois comments
EXPLAIN EXTENDED SELECT A.a, A.b, B.c FROM B FORCE INDEX (idx_B_c) JOIN A ON A.b = B.b WHERE A.a = 44 ORDER BY B.c;
EXPLAIN EXTENDED SELECT A.a, A.b, B.c FROM A JOIN B ON A.b = B.b WHERE A.a = 44 ORDER BY B.c LIMIT 10;
EXPLAIN EXTENDED SELECT A.a, A.b, B.c FROM B FORCE INDEX (idx_B_c) JOIN A ON A.b = B.b WHERE A.a = 44 ORDER BY B.c LIMIT 10;
La clasificación de archivos se produce en su cláusula ORDER BY. ¿Cómo se indexa 'B.c'? – jason
@jason: He actualizado el SQL en la publicación para que sea un poco más legible. La indexación debería ser clara ahora. – Paso