índice O lógico de dos columnas de la base de datos, o crear una tabla de 'índice' separada
-
13-12-2019 - |
Pregunta
Tengo esta siguiente tabla:
Matches -> match_id, team_a_id , team_b_id, score
Esta tabla registrará los partidos entre dos equipos (equipo A y equipo B).Sin embargo, a veces el equipo A juega como anfitrión y otras veces el equipo B juega como anfitrión.Por lo tanto, cuando intenté encontrar coincidencias históricas entre el equipo a y el equipo b.Lo que estoy haciendo actualmente es
select * from matches where (team_a_id = 1 and team_b_id = 2) or (team_a_id = 2 and team_b_id = 1);
¿Existe algún enfoque mejor para tal caso?En cuanto a la consulta anterior, ¿tengo razón al incluir un índice de combinación team_a_id y team_b_id?Pero aun así, todavía tengo una condición OR lógica entre AB O BA.
Alternativamente, Tengo otra idea, que es tener otra mesa digamos historia
History -> team_hash, match_id
Construyo manualmente team_hash donde hash(a,b) == hash(b,a)
.Pero esto da como resultado una inserción ligeramente más lenta pero una lectura más rápida.¿O es realmente una lectura más rápida?
Solución
Suponiendo que existe un índice compuesto en {team_a_id, team_b_id}
, el DBMS puede ejecutar su declaración SQL utilizando sólo dos búsquedas de índice (una para el team_a_id = 1 and team_b_id = 2
y el otro para el team_a_id = 2 and team_b_id = 1
), que es muy rápido.No espero que le falte rendimiento.
Sin embargo, existe una manera de eliminar una de estas búsquedas de índice.Añade una restricción...
CHECK(team_a_id < team_b_id)
...y codificar una "dirección" (es decir,qué equipo es el anfitrión) en un campo separado si es necesario.De esta manera ya sabes team_a_id = 2 and team_b_id = 1
nunca puede ser cierto, así que sólo necesitas buscar en team_a_id = 1 and team_b_id = 2
.
El hash "simétrico" es una buena idea, pero:
- La exactitud del hash no se puede imponer de forma declarativa; deberá hacerlo mediante un activador o en el nivel de la aplicación.
- Es un dato redundante.Tendrás que mantener
team_a_id
yteam_b_id
de todos modos para resolver conflictos de hash.Datos más grandes significan efectivamente un caché más pequeño. - De hecho, puede aumentar el número de índices; la aplicación eficiente de la integridad referencial probablemente requerirá índices en
team_a_id
yteam_b_id
incluso si no los necesita para la consulta SQL real.Además de ejercer más presión sobre el caché, se debe mantener cada índice adicional, lo que podría perjudicar el rendimiento de INSERT/UPDATE/DELETE.La situación es especialmente grave en InooDB, donde no se puede desactivar la agrupación en clústeres, por lo que los índices secundarios tienden a ser más caros que en las tablas basadas en montón (consulte "Desventajas de la agrupación en clústeres" en Este artículo).
Otros consejos
También puedes hacer que tu cláusula WHERE sea algo como esto
((team_a_id = 1 and team_b_id = 2) or (team_a_id = 2 and team_b_id = 1))
AND team_a_id IN (1,2) AND team_b_id IN (1,2)
de esta manera será posible utilizar un índice como (team_a_id,team_b_id).