Eu tenho uma tabela geográfica que contém
- países
- localidades (cidade, vila, vila, ilha, arquipélago)
- locais (local/empresa + bairros/distrito/área), por exemplo - Big Ben ou Southwark Borough.
Para detalhes adicionais de cada tipo de local, tenho tabelas relacionadas.
Tabela 'country_details' para locais do tipo 'country' e da mesma forma para locais.
Para um local como 'Big Ben', tem referência ao id da sua localidade (ou seja, Londres), e também referência ao país (que pode ser simplesmente pelo iso_code do país)
Exemplo:
id | title | locality_id | country_iso_code |
---------------------------------------------------------|
1 | United Kingdom | null | UK |
2 | London | null | UK |
3 | Big Ben | 2 | UK |
4 | XYZ District | 2 | UK |
Cenário
Agora, como para enviar ao cliente informações sobre o Big Ben eu também gostaria de obter o nome da localidade (Londres) e do país (Reino Unido), parece que minhas únicas 2 opções são:
- CTE recursivo
- JOIN na mesma mesa.
No entanto, uma vez que temos uma tabela de dezenas de milhares de registros, que pode potencialmente crescer para muito mais (alguns milhões), além da complexidade da consulta, isso também afetará o desempenho, suponho.
Pergunta
Qual é a melhor opção para "juntar" detalhes como "Londres" e "Reino Unido"?
Ambas as opções são ruins e é melhor repensar o design do esquema?
Tabelas:
CREATE TABLE places (
id int,
type smallint, -- ['country', 'locality', 'location']
sub_type smallint, -- nullable (city, village, etc.)
-- names
title text,
-- locality
locality_name text,
locality_id
-- country
country_iso_alpha2 text, -- 'GB'
country_name text, -- 'United Kingdom'
admin_region text, -- 'England', 'Texas', .. (null for Country)
...
);
CREATE TABLE country_details(
place_id int,
place_type smallint NOT NULL CHECK (item_type=1),
iso_alpha2 text,
iso_alpha3 text,
...
PRIMARY KEY (place_id, place_type),
FOREIGN KEY (place_id, place_type) references places (place_id, place_type) ON DELETE CASCADE
);
CREATE TABLE location_details(
place_id int,
place_type smallint NOT NULL CHECK (item_type=3),
website text,
neighborhood text,
formatted_address text,
...
PRIMARY KEY (place_id, place_type),
FOREIGN KEY (place_id, place_type) references places (place_id, place_type) ON DELETE CASCADE
);