Atualmente, o MySQL não suporta índices condicionais.
Para obter o que você está perguntando (não que você deva fazê-lo;)), você pode começar a criar uma tabela 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`)
);
Então você adiciona três gatilhos na tabela 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 ;
Precisamos delimiter //
porque queremos usar ;
dentro dos gatilhos.
Dessa forma, a tabela auxiliar conterá exatamente os IDs correspondentes às linhas principais da tabela que contêm a sequência "ACTIVE", sendo atualizada pelos gatilhos.
Para usar isso em um select
, você pode usar o habitual join
:
SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
ON auxiliary_table.id = main_table.id
ORDER BY auxiliary_table.name;
Se a tabela principal já contiver dados, ou caso você faça alguma operação externa que altere os dados de maneira incomum (EG: fora do MySQL), você pode corrigir a tabela auxiliar com isso:
INSERT INTO auxiliary_table SET
id = main_table.id,
name = main_table.name,
WHERE main_table.status="ACTIVE";
Sobre o desempenho, provavelmente você terá inserções, atualizações e exclusões mais lentas. Isso pode fazer algum sentido apenas se você realmente lidar com alguns casos em que a condição desejada é positiva. Mesmo assim, provavelmente apenas testando você pode ver se o espaço economizado realmente justifica essa abordagem (e se você realmente está economizando algum espaço).
Você não pode fazer a indexação condicional, mas, por exemplo, você pode adicionar um índice de várias colunas em (
name
,status
).Mesmo que indexe todos os dados nessas colunas, ainda o ajudará a encontrar os nomes que você está procurando com o status "ativo".
fonte
Você pode fazer isso dividindo os dados entre duas tabelas, usando visualizações para unir as duas tabelas quando todos os dados forem necessários e indexando apenas uma das tabelas nessa coluna - mas acho que isso causaria problemas de desempenho para consultas que precisam executar sobre a tabela inteira, a menos que o planejador de consultas seja mais inteligente do que eu acredito. Essencialmente, você particionaria manualmente a tabela (e aplicaria o índice a apenas uma das partições).
Infelizmente, o recurso de particionamento de tabela embutido não o ajudará em sua busca, pois você não pode aplicar um índice a uma única partição.
Você pode manter uma coluna extra com um índice e ter apenas um valor nessa coluna quando a condição na qual você deseja basear o índice for verdadeira, mas é provável que seja trabalhoso e tenha um valor limitado (ou negativo) em termos de eficiência de consulta e economia de espaço.
fonte
O MySQL agora possui colunas virtuais, que podem ser usadas para índices.
fonte
select count(*) from foo where id is null ;
usar um índice?)decode(status,'ACTIVE',name,null)
por exemplo.