MySQL actualmente no admite índices condicionales.
Para lograr lo que está pidiendo (no es que deba hacerlo;)) puede comenzar a crear una tabla auxiliar:
CREATE TABLE `my_schema`.`auxiliary_table` (
`id` int unsigned NOT NULL,
`name` varchar(250), /* specify the same way as in your main table */
PRIMARY KEY (`id`),
KEY `name` (`name`)
);
Luego agrega tres disparadores en la tabla principal:
delimiter //
CREATE TRIGGER example_insert AFTER INSERT ON main_table
FOR EACH ROW
BEGIN
IF NEW.status = 'ACTIVE' THEN
REPLACE auxiliary_table SET
auxiliary_table.id = NEW.id,
auxiliary_table.name = NEW.name;
END IF;
END;//
CREATE TRIGGER example_update AFTER UPDATE ON main_table
FOR EACH ROW
BEGIN
IF NEW.status = 'ACTIVE' THEN
REPLACE auxiliary_table SET
auxiliary_table.id = NEW.id,
auxiliary_table.name = NEW.name;
ELSE
DELETE FROM auxiliary_table WHERE auxiliary_table.id = OLD.id;
END IF;
END;//
CREATE TRIGGER example_delete AFTER DELETE ON main_table
FOR EACH ROW
BEGIN
DELETE FROM auxiliary_table WHERE auxiliary_table.id = OLD.id;
END;//
delimiter ;
Necesitamos delimiter //
porque queremos usar ;
dentro de los disparadores.
De esa manera, la tabla auxiliar contendrá exactamente los ID correspondientes a las filas de la tabla principal que contienen la cadena "ACTIVE", que se actualizarán mediante los desencadenantes.
Para usar eso en un select
, puede usar lo habitual join
:
SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
ON auxiliary_table.id = main_table.id
ORDER BY auxiliary_table.name;
Si la tabla principal ya contiene datos, o si realiza alguna operación externa que cambia los datos de una manera inusual (por ejemplo, fuera de MySQL), puede arreglar la tabla auxiliar con esto:
INSERT INTO auxiliary_table SET
id = main_table.id,
name = main_table.name,
WHERE main_table.status="ACTIVE";
Sobre el rendimiento, probablemente tendrá inserciones, actualizaciones y eliminaciones más lentas. Esto puede tener sentido solo si realmente maneja pocos casos en los que la condición deseada es positiva. Incluso de esa manera, probablemente solo probando puede ver si el espacio ahorrado realmente justifica este enfoque (y si realmente está ahorrando espacio).
No puede hacer indexación condicional, pero para su ejemplo, puede agregar un índice de varias columnas en (
name
,status
).Aunque indexará todos los datos en esas columnas, aún lo ayudará a encontrar los nombres que está buscando con el estado "activo".
fuente
Puede hacerlo dividiendo los datos entre dos tablas, utilizando vistas para unir las dos tablas cuando se necesitan todos los datos e indexando solo una de las tablas en esa columna, pero creo que esto causaría problemas de rendimiento para las consultas que necesitan recorra toda la tabla a menos que el planificador de consultas sea más inteligente de lo que yo le atribuyo. Esencialmente, estaría particionando manualmente la tabla (y aplicando el índice a solo una de las particiones).
Desafortunadamente, la función de particionamiento de tabla incorporada no lo ayudará en su búsqueda, ya que no puede aplicar un índice a una sola partición.
Podría mantener una columna adicional con un índice y solo tener un valor en esa columna cuando la condición en la que desea que se base el índice sea verdadera, pero es probable que esto requiera mucho trabajo y un valor limitado (o negativo) en términos de consulta de eficiencia y ahorro de espacio.
fuente
MySQL ahora tiene columnas virtuales, que pueden usarse para índices.
fuente
select count(*) from foo where id is null ;
utilizar un índice?)decode(status,'ACTIVE',name,null)
por ejemplo.