Para tener un índice parcial similar a PostgreSQL en MySQL 5.5

9

Tengo datos grandes donde solo selecciono un pequeño intervalo de datos a la vez, de modo que la selección siempre esté en una secuencia. Estoy tratando de implementar PostgreSQL como índice parcial en MySQL que está dirigido para tales fines. No estoy seguro de si la restricción única parcial es la misma que la que quiero.

Código en PostgreSQL 9.4

CREATE UNIQUE INDEX dir_events
    ON events (measurement_id)
    USING btree
    (eventBody)
    WHERE is_active;

Intento en el índice parcial de ypercube en MySQL

CREATE UNIQUE INDEX dir_events
    [index_type] -- TODO what here?
    ON events (measurement_id, is_active)
    [index_type] -- TODO what here?

¿Cómo puede crear un índice parcial similar a PostgreSQL en MySQL 5.5 o similar?

Léo Léopold Hertz 준영
fuente
44
MySQL no ha implementado índices parciales. Puede agregar otra tabla en su diseño que almacene solo las filas con is_active = TRUE(o que solo tenga una columna, el PK de dir_events).
ypercubeᵀᴹ

Respuestas:

13

Ni MySQL ni los hermanos (MariaDB, Drizzle, etc.) han implementado índices parciales.

Lo que puede hacer, teniendo en cuenta esta restricción:

  • a) hacer un índice simple (no parcial) en (is_active, measurement_id). Se utilizará en consultas donde lo haría el índice parcial. Por supuesto, si la is_activecolumna es 3% verdadera y 97% falsa, este índice será mucho mayor (que un índice parcial). Pero aún más pequeño que la tabla y útil para estas consultas.
    Otra limitación es que el índice no puede estar UNIQUEcon esta solución, por lo que la restricción no se aplica. Si se crea el índice con UNIQUE, la unicidad también se aplicará para las filas con is_active = FALSE. Asumo que no quieres eso:

    CREATE INDEX dir_events
        ON events (is_active, measurement_id)
        USING btree ;
    
  • b1) (la variación simple de b): agregue otra tabla en su diseño, con solo las columnas de clave principal eventsy una clave externa para events. Esta tabla solo debe tener filas donde is_activesea ​​verdadero en la tabla original (esto se aplicará por su aplicación / procedimientos). Las consultas con is_active = TRUEsería cambiado a unirse a la mesa (en lugar de la WHEREcondición.)
    El UNIQUEno es imperativo, ya sea con esta solución, pero las consultas sólo lo haría un simple unirse (a un índice mucho menor) y deben ser muy eficientes:

    CREATE TABLE events_active
    ( event_id INT NOT NULL,         -- assuming an INT primary key on events
      PRIMARY KEY (event_id),
      FOREIGN KEY (event_id)
        REFERENCES events (event_id)
    ) ;
    
    INSERT INTO events_active 
      (event_id)
    SELECT event_id
    FROM events
    WHERE is_active = TRUE ;
    
  • b2) una solución más compleja: agregue otra tabla en su diseño, con solo las columnas de clave principal de la tabla ymeasurement_id . Como en la sugerencia anterior, esta tabla solo debe tener filas donde is_activesea ​​verdadero en la tabla original (esto también será aplicado por su aplicación / procedimientos). Luego, utilice esta tabla solo para consultas que tengan WHERE is_active = TRUEy necesiten solo la measurement_idcolumna. Si se necesitan más columnas events, deberá hacerlo join, como antes.
    La UNIQUErestricción se puede hacer cumplir con esta solución. La duplicación de measurement_idcolumna también se puede asegurar para que sea coherente (con una restricción única adicional eventsy una clave foránea compuesta):

    ALTER TABLE events
      ADD UNIQUE (event_id, measurement_id) ;
    
    CREATE TABLE events_active
    ( event_id INT NOT NULL,
      measurement_id INT NOT NULL.
      PRIMARY KEY (event_id, measurement_id),
      UNIQUE (measurement_id),
      FOREIGN KEY (event_id, measurement_id)
        REFERENCES events (event_id, measurement_id)
    ) ;
    
    INSERT INTO events_active 
      (event_id, measurement_id)
    SELECT event_id, measurement_id
    FROM events
    WHERE is_active = TRUE ;
    
  • c) quizás el más simple de todos: use PostgreSQL. Estoy seguro de que hay paquetes para su distribución de Linux. Puede que no sean la última versión de Postgres, pero se agregaron índices parciales en 7.0 (o anterior), por lo que no debería tener un problema. Además, estoy seguro de que podría instalar la última versión en casi cualquier distribución de Linux, incluso con una pequeña molestia. Solo necesita instalarlo una vez.

ypercubeᵀᴹ
fuente
Gran respuesta. Segway: La wiki sobre índices parciales cita un blog "En MySQL, el término" índice parcial "a veces se usa para referirse a los índices de prefijo", que no se menciona en ninguna parte de los documentos de MySQL. Es una terminología confusa acuñada en ese blog. El blog también afirma que los índices de prefijo son más pequeños / de rendimiento, lo que dependería. Un prefijo de cadena crearía un btree con menos profundidad, aún más páginas por hoja, por lo que los escaneos de índice pueden ser más rápidos; las búsquedas serían más lentas. Además, use PostgreSQL! La primera mención de PG que encontré es este extraño documento de opinión en v7.0 postgresql.org/docs/7.0/partial-index.htm
Davos
0

No es lo ideal, pero si tiene validación en el campo, puede hacer un cambio que invalide el valor. Por ejemplo, caracteres ilegales o números negativos. Puede realizar este cambio cuando se elimina suavemente y sabe que no entrará en conflicto con un valor válido. También debe estar atento a los valores eliminados suaves que no entren en conflicto entre sí.

En 1 caso, tenía una columna de correo electrónico con una restricción única y una identificación de entero de incremento automático para cada fila. En la eliminación suave, agregué "id @", donde id era la ID de fila única, antes del correo electrónico real. @no está permitido en los correos electrónicos a menos que se cite, por lo que sé que ningún correo electrónico válido chocará con el nuevo valor, por lo que esto nunca chocará con un correo electrónico válido. La ID entera única también garantiza que cada fila eliminada será única, incluso si el mismo correo electrónico se elimina varias veces.

Sé que esto no es ideal, pero es una forma simple de solucionar el problema.

NOTA: El cambio que menciono agrega caracteres al campo único, por lo que tuve que hacer trucos adicionales si el valor actual ya está en / cerca de la longitud máxima. Son específicos de la aplicación, por lo que no vale la pena mencionarlos aquí, pero tenga en cuenta y encuentre una solución para eso también, y esta es una forma simple de evitar perder la función de índice parcial.

Charles L.
fuente