- Quando devo usar um índice composto em um banco de dados?
- Quais são as ramificações de desempenho usando um índice composto)?
- Por que devo usar um índice composto?
Por exemplo, eu tenho uma homes
tabela:
CREATE TABLE IF NOT EXISTS `homes` (
`home_id` int(10) unsigned NOT NULL auto_increment,
`sqft` smallint(5) unsigned NOT NULL,
`year_built` smallint(5) unsigned NOT NULL,
`geolat` decimal(10,6) default NULL,
`geolng` decimal(10,6) default NULL,
PRIMARY KEY (`home_id`),
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
) ENGINE=InnoDB ;
Faz sentido usar um índice composto para ambos geolat
e geolng
, de modo que:
Eu substituo:
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
com:
KEY `geolat_geolng` (`geolat`, `geolng`)
Se então:
- Por quê?
- Qual é a ramificação do desempenho usando um índice composto)?
ATUALIZAR:
Como muitas pessoas afirmaram que é totalmente dependente das consultas que realizo, a seguir é apresentada a consulta mais comum:
SELECT * FROM homes
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???
ATUALIZAÇÃO 2:
Com o seguinte esquema do banco de dados:
CREATE TABLE IF NOT EXISTS `homes` (
`home_id` int(10) unsigned NOT NULL auto_increment,
`primary_photo_group_id` int(10) unsigned NOT NULL default '0',
`customer_id` bigint(20) unsigned NOT NULL,
`account_type_id` int(11) NOT NULL,
`address` varchar(128) collate utf8_unicode_ci NOT NULL,
`city` varchar(64) collate utf8_unicode_ci NOT NULL,
`state` varchar(2) collate utf8_unicode_ci NOT NULL,
`zip` mediumint(8) unsigned NOT NULL,
`price` mediumint(8) unsigned NOT NULL,
`sqft` smallint(5) unsigned NOT NULL,
`year_built` smallint(5) unsigned NOT NULL,
`num_of_beds` tinyint(3) unsigned NOT NULL,
`num_of_baths` decimal(3,1) unsigned NOT NULL,
`num_of_floors` tinyint(3) unsigned NOT NULL,
`description` text collate utf8_unicode_ci,
`geolat` decimal(10,6) default NULL,
`geolng` decimal(10,6) default NULL,
`display_status` tinyint(1) NOT NULL,
`date_listed` timestamp NOT NULL default CURRENT_TIMESTAMP,
`contact_email` varchar(100) collate utf8_unicode_ci NOT NULL,
`contact_phone_number` varchar(15) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`home_id`),
KEY `customer_id` (`customer_id`),
KEY `city` (`city`),
KEY `num_of_beds` (`num_of_beds`),
KEY `num_of_baths` (`num_of_baths`),
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
KEY `account_type_id` (`account_type_id`),
KEY `display_status` (`display_status`),
KEY `sqft` (`sqft`),
KEY `price` (`price`),
KEY `primary_photo_group_id` (`primary_photo_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=8 ;
Usando o seguinte SQL:
EXPLAIN SELECT homes.home_id,
address,
city,
state,
zip,
price,
sqft,
year_built,
account_type_id,
num_of_beds,
num_of_baths,
geolat,
geolng,
photo_id,
photo_url_dir
FROM homes
LEFT OUTER JOIN home_photos ON homes.home_id = home_photos.home_id
AND homes.primary_photo_group_id = home_photos.home_photo_group_id
AND home_photos.home_photo_type_id = 2
WHERE homes.display_status = true
AND homes.geolat BETWEEN -100 AND 100
AND homes.geolng BETWEEN -100 AND 100
EXPLAIN retorna:
id select_type table type possible_keys key key_len ref rows Extra
----------------------------------------------------------------------------------------------------------
1 SIMPLE homes ref geolat,geolng,display_status display_status 1 const 2 Using where
1 SIMPLE home_photos ref home_id,home_photo_type_id,home_photo_group_id home_photo_group_id 4 homes.primary_photo_group_id 4
Não entendo muito bem como ler o comando EXPLAIN. Isso parece bom ou ruim. No momento, não estou usando um índice composto para geolat e geolng. Eu deveria ser?
fonte
WHERE geolat BETWEEN ??? AND ??? AND geolng BETWEEN ??? AND ???
. Parará após o primeiro campo. A resposta de "Question Overflow" explica o porquê.Imagine que você tem as três consultas a seguir:
Consulta I:
Consulta II:
Consulta III:
Se você tiver um índice separado por coluna, todas as três consultas usarão índices. No MySQL, se você tiver um índice composto (
geolat
,geolng
), apenas as consultas I e II (que estão usando a primeira parte do índice composto) usam índices. Nesse caso, a consulta III requer pesquisa de tabela completa.Na seção Índices de Colunas Múltiplas do manual, é explicado claramente como os índices de colunas funcionam, portanto, não quero redigitar o manual.
Na página Manual de Referência do MySQL :
Se você usar um índice separado para as colunas geolat e geolng, você terá dois índices diferentes em sua tabela que poderão ser pesquisados independentemente.
Se você usar o índice composto, terá apenas um índice para as duas colunas:
RRN é o número de registro relativo (para simplificar, você pode dizer ID). Os dois primeiros índices gerados separadamente e o terceiro índice é composto. Como você pode ver, é possível pesquisar com base em geolng no composto, uma vez que é indexado por geolat, no entanto, é possível pesquisar por geolat ou "geolat AND geolng" (já que geolng é o índice de segundo nível).
Além disso, dê uma olhada na seção de manual Como o MySQL usa índices .
fonte
BETWEEN
), nenhum outro campo do índice é considerado! Portanto, o índice composto não é melhor.Pode haver um equívoco sobre o que o índice composto faz. Muitas pessoas pensam que o índice composto pode ser usado para otimizar uma consulta de pesquisa, desde que a
where
cláusula cubra as colunas indexadas, no seu casogeolat
egeolng
. Vamos nos aprofundar mais:Acredito que seus dados sobre as coordenadas das casas seriam decimais aleatórios, assim:
Desde que
geolat
egeolng
valores dificilmente se repetem. Um índice compostogeolat
egeolng
ficaria assim:Portanto, a segunda coluna do índice composto é basicamente inútil ! A velocidade da sua consulta com um índice composto provavelmente será semelhante a um índice apenas na
geolat
coluna.Como mencionado por Will, o MySQL fornece suporte a extensão espacial . Um ponto espacial é armazenado em uma única coluna em vez de duas
lat
lng
colunas separadas . O índice espacial pode ser aplicado a essa coluna. No entanto, a eficiência pode ser superestimada com base na minha experiência pessoal. Pode ser que o índice espacial não resolva o problema bidimensional, mas apenas acelere a pesquisa usando R-Trees com divisão quadrática .A desvantagem é que um ponto espacial consome muito mais memória ao usar números de precisão dupla de oito bytes para armazenar coordenadas. Corrija-me se eu estiver errada.
fonte
Os índices compostos são muito poderosos, pois:
APLICAR A INTEGRIDADE DA ESTRUTURA
Os índices compostos não são apenas outro tipo de índice; eles podem fornecer estrutura NECESSÁRIA a uma tabela, reforçando a integridade como a Chave Primária.
O Innodb do Mysql suporta clustering e o exemplo a seguir ilustra por que um índice composto pode ser necessário.
Para criar um amigos tabelas (ou seja, para uma rede social) precisamos de 2 colunas:
user_id, friend_id
.Strcture da tabela
Por virtude, uma Chave Primária (PK) é única e, ao criar uma PK composta, o Innodb verifica automaticamente se não há duplicatas
user_id, friend_id
quando um novo registro é adicionado. Esse é o comportamento esperado, pois nenhum usuário deve ter mais de 1 registro (link de relacionamento),friend_id = 2
por exemplo.Sem uma PK composta, podemos criar esse esquema usando uma chave substituta:
Agora, sempre que um novo registro for adicionado, teremos que verificar se um registro anterior com a combinação
user_id, friend_id
ainda não existe.Como tal, um índice composto pode impor a integridade da estrutura.
ATIVAR A CLASSIFICAÇÃO EM UM ID FILTRADO
É muito comum classificar um conjunto de registros pela hora da postagem (carimbo de data / hora ou data / hora). Normalmente, isso significa postar em um determinado ID. Aqui está um exemplo
Tabela User_Wall_Posts (pense se as publicações no mural do Facebook)
Queremos consultar e localizar todas as postagens
user_id = 10
e classificar as postagens dos comentários portimestamp
(data).SQL QUERY
A PK composta permite ao Mysql filtrar e classificar os resultados usando o índice; O Mysql não precisará usar um arquivo temporário ou tipo de arquivo para buscar os resultados. Sem uma chave composta, isso não seria possível e causaria uma consulta muito ineficiente.
Como tal, as chaves compostas são muito poderosas e se adaptam mais ao simples problema de "Eu quero procurar,
column_a, column_b
então usarei chaves compostas. Para o meu esquema de banco de dados atual, tenho tantas chaves compostas quanto chaves únicas. Não ignore uso de uma chave composta!fonte
Índices compostos são úteis para
Um índice composto não pode manipular dois intervalos. Discuto isso mais adiante no meu livro de receitas do índice .
Encontre o mais próximo - se a pergunta é realmente sobre como otimizar
então, nenhum índice pode realmente lidar com ambas as dimensões.
Em vez disso, é preciso "pensar fora da caixa". Se uma dimensão for implementada por meio de particionamento e a outra for escolhida com cuidado
PRIMARY KEY
, é possível obter uma eficiência significativamente melhor para tabelas muito grandes de pesquisa de lat / lng. Meu blog latlng aborda os detalhes de como implementar "encontrar o mais próximo" no mundo. Inclui código.O
PARTITIONs
são listras de gamas de latitude. OPRIMARY KEY
deliberadamente começa com longitude, de modo que as linhas úteis provavelmente estejam no mesmo bloco. Uma Rotina Armazenada orquestra o código confuso para fazerorder by... limit...
e aumentar o 'quadrado' ao redor do alvo até que você tenha cafés suficientes (ou o que seja). Ele também cuida dos cálculos do grande círculo e da manipulação da linha de dados e dos pólos.Mais
Eu escrevi outro blog; ele compara 5 maneiras de fazer pesquisas lat / lng: http://mysql.rjweb.org/doc.php/latlng#representation_choices (faz referência ao link fornecido acima como um dos 5.) Uma das outras maneiras é essa, e ressalta que eles são ideais para o caso específico :
Ou seja, é importante ter as duas colunas em dois índices e não ter índices de coluna única no geolat e no geolng.
fonte
Não há preto e branco, um tamanho serve para todas as respostas.
Você deve usar um índice composto, quando sua carga de trabalho de consulta se beneficiaria de um.
Você precisa perfilar sua carga de trabalho de consulta para determinar isso.
Um índice composto entra em jogo quando as consultas podem ser satisfeitas inteiramente a partir desse índice.
UPDATE (em resposta à edição da pergunta publicada): se você estiver selecionando * da tabela, o índice composto pode ser usado, mas não pode. Você precisará executar o EXPLAIN PLAN para ter certeza.
fonte
Para fazer pesquisas espaciais, você precisa de um algoritmo R-Tree , que permita pesquisar áreas geográficas muito rapidamente. Exatamente o que você precisa para este trabalho.
Alguns bancos de dados possuem índices espaciais embutidos. Uma rápida pesquisa no Google mostra que o MySQL 5 os possui (que, olhando seu SQL, acho que você está usando o MySQL).
fonte
O índice composto pode ser útil quando você deseja otimizar a
group by
cláusula (consulte este artigo http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html ). Por favor preste atenção:fonte
GROUP BY
não foi mencionado.GROUP BY
não foi mencionado pelo OP.Estou com @Mitch, depende inteiramente de suas perguntas. Felizmente, você pode criar e soltar índices a qualquer momento e acrescentar a palavra-chave EXPLAIN às suas consultas para ver se o analisador de consultas usa os índices.
Se você estiver procurando um par exato de lat / long, esse índice provavelmente faria sentido. Mas você provavelmente procurará casas a uma certa distância de um determinado local, para que suas consultas sejam mais ou menos assim (consulte a fonte ):
e o índice provavelmente não será útil. Para consultas geoespaciais, você precisa de algo como este .
Atualização: com esta consulta:
O analisador de consultas pode usar um índice somente no geolat, ou um índice apenas no geolng, ou possivelmente os dois índices. Eu não acho que usaria um índice composto. Mas é fácil testar cada uma dessas permutações em um conjunto de dados real e (a) ver o que EXPLAIN diz a você e (b) medir o tempo que a consulta realmente leva.
fonte