- O grafo de propriedades do Postgres 19 é um recurso de SQL/PGQ que declara tabelas existentes como vértices e arestas e pesquisa padrões fixos de relacionamento com
MATCH, sem copiar dados nem criar um mecanismo de execução de grafos separado
- Os padrões de grafo são compilados em joins relacionais, reutilizando o otimizador, os índices e as estatísticas existentes, então até travessias lentas podem ser analisadas e otimizadas da mesma forma que joins comuns
- Tabelas de dimensão correspondem naturalmente a vértices, e tabelas de junção puras a arestas, mas tabelas fato com várias chaves estrangeiras e propriedades próprias são mais adequadas para modelagem como vértices-hub que representam eventos
- É possível declarar a mesma tabela ao mesmo tempo como vértice e como várias arestas usando aliases diferentes, então não é necessário criar nem armazenar tabelas de aresta separadas usando as chaves estrangeiras já existentes em
results
- Como o Postgres 19 não oferece suporte a caminhos de comprimento variável, ele não é adequado para menor caminho, alcançabilidade em N saltos ou PageRank; funciona melhor para buscas de comprimento fixo quando a estrutura relacional já é conhecida
Como ler um esquema relacional como grafo
- Em um esquema relacional normalizado, tabelas de dimensão como
drivers, constructors e circuits armazenam entidades, enquanto tabelas fato registram eventos como resultados de corrida ou sessões classificatórias
- Cada linha é um vértice em potencial, e chaves estrangeiras são arestas em potencial que apontam para outras linhas
- Um diagrama ER corresponde a um grafo no nível do esquema
- As linhas reais e seus relacionamentos por chave estrangeira correspondem a um grafo no nível da instância
- Um pedido como “encontrar o constructor correspondente a cada resultado” é uma travessia de grafo que, em SQL relacional, seria escrita como
results JOIN constructors ON ...
- O SQL/PGQ não adiciona um novo grafo em si; em vez de listar joins manualmente, ele permite escrever a pergunta na forma de grafo
- A abordagem do RelBench leva tabelas para pandas e monta um grafo PyTorch em memória, enquanto o grafo de propriedades do Postgres usa diretamente os relacionamentos já existentes entre tabelas dentro do banco de dados
- Os exemplos do PyG também usam principalmente arquivos planos ou grafos em memória
- O código do experimento com o conjunto de dados de Fórmula 1 pode ser visto no repositório no GitHub
Composição de um grafo de propriedades
CREATE PROPERTY GRAPH é um objeto declarativo nomeado criado sobre tabelas existentes
VERTEX TABLES especifica quais tabelas terão suas linhas lidas como vértices
EDGE TABLES especifica quais tabelas terão suas linhas lidas como relacionamentos de ligação
- Para cada tabela de vértice, são definidos os seguintes elementos
KEY: identificador do vértice, normalmente a chave primária
LABEL: nome do tipo de vértice usado em MATCH
PROPERTIES: lista de colunas acessíveis nas consultas de grafo
- Para cada tabela de aresta, definem-se
SOURCE e DESTINATION, e ambos referenciam as chaves dos vértices
CREATE PROPERTY GRAPH não move nem copia os dados
- As linhas continuam nas tabelas originais
- A declaração apenas define como ler a estrutura existente de chaves estrangeiras como grafo
- Os elementos estruturais de um grafo de propriedades são de apenas dois tipos: vértices e arestas
- Labels e propriedades são atributos pertencentes a um vértice ou a uma aresta
- No
psql, o Element Kind de cada elemento é vertex ou edge
Consultando padrões fixos com MATCH
- Consultas de grafo são escritas colocando um padrão
MATCH dentro de GRAPH_TABLE(...)
- O padrão abaixo representa o relacionamento que vai de driver para race passando por result
MATCH (d IS driver)<-[IS of_driver]-(res IS result)-[IS in_race]->(ra IS race)
- A cláusula
COLUMNS define quais colunas da consulta de grafo serão retornadas para fora
- No
SELECT externo, o resultado de GRAPH_TABLE(...) pode ser consultado como uma tabela comum
- Como o padrão inclui direção e labels, o relacionamento pode ser lido como uma frase, o que facilita entender a estrutura em comparação com o mesmo caso usando múltiplos joins
Estrutura convertida em joins relacionais na execução
MATCH não é um mecanismo de execução de grafos separado acoplado ao Postgres; é uma sintaxe compilada em joins relacionais
- Ao executar
EXPLAIN no padrão driver–result–race, aparecem quatro hash joins sobre as tabelas de base
- Assim como nos joins escritos manualmente, ele usa
- o otimizador já existente do Postgres
- os índices já existentes
- as estatísticas já existentes
- Se uma travessia de grafo estiver lenta, a causa e a forma de otimizar serão as mesmas de um join comum lento
- Também é possível inspecionar grafos no
psql com comandos parecidos com os de tabelas
\dG: mostra a lista de grafos de propriedades
\d f1: mostra cada vértice e aresta, a tabela de base, o tipo de elemento e os vértices de origem e destino das arestas
\d+ f1: reconstrói toda a instrução CREATE PROPERTY GRAPH, incluindo a chave da aresta inferida a partir da chave primária da tabela de aresta
Diferença entre chaves e propriedades
- Uma coluna definida como
KEY de um vértice não se torna automaticamente uma propriedade
- Se
driver_id for definido apenas como chave do vértice, um filtro como d.driver_id = 1 falhará porque essa coluna não é uma propriedade consultável
- A chave identifica o vértice, mas não o expõe à consulta
- Para filtrar ou retornar uma coluna de ID, é preciso adicioná-la explicitamente à lista de
PROPERTIES
Limitação de caminhos de comprimento variável no Postgres 19
- O Postgres 19 não oferece suporte a quantificadores de padrão de elemento como seguir uma aresta de 1 a 3 vezes
ERROR: element pattern quantifier is not supported
- Para percorrer dois saltos, é preciso declarar explicitamente dois padrões de aresta em
MATCH
- Caminhos de comprimento arbitrário não podem ser expressos com a sintaxe de grafo de propriedades
- Buscas com profundidade aberta precisam ser tratadas com CTE recursiva sobre as tabelas de base, o que fica fora da sintaxe de grafo de propriedades
Mapeando tabelas existentes para vértices e arestas
-
Tabelas de dimensão como vértices
- Tabelas de entidades com chave primária estável e atributos, como
drivers, constructors e circuits, correspondem diretamente a vértices
- Basta usar a chave primária como chave do vértice e expor como propriedades as colunas necessárias
-
Tabelas de junção puras como arestas
- Tabelas-ponte muitos-para-muitos como
student_courses(student_id, course_id) têm como função original ligar duas entidades, então correspondem naturalmente a arestas
- Uma chave estrangeira é declarada como vértice de origem e a outra como vértice de destino
- Como cada linha da tabela de junção já é um relacionamento, não é necessária nenhuma transformação adicional de dados para o grafo
- Nessa estrutura,
students e courses são vértices, e student_courses se torna a aresta enrolled_in
-
Tabelas fato como vértices de evento
- Linhas de
results apontam para três entidades — driver, race e constructor — e ainda têm dados próprios como grid, position, points e status
- Como arestas em SQL/PGQ são relações binárias com uma origem e um destino, não dá para transformar uma linha inteira com três chaves estrangeiras em uma única aresta
- Se a própria linha fato for objeto de análise, é mais adequado declarar essa tabela como vértice
- O vértice
results armazena o evento e suas propriedades
- Arestas estreitas como
results_driver, results_race e results_constructor conectam esse vértice às entidades externas
- Esse modelo cria uma estrutura de hub como
driver <- result -> race, na qual é possível parar no vértice result para filtrar ou consultar propriedades
- Se o objeto de interesse for o relacionamento em si, modele como aresta; se for uma linha específica ou evento com propriedades próprias, modele como vértice
- Tabelas de junção representam relacionamentos, enquanto tabelas fato representam eventos
Usando a mesma tabela ao mesmo tempo como vértice e aresta
- A distinção “vértice ou aresta” não se aplica à tabela de base, e sim a cada declaração de elemento no grafo
- A mesma tabela pode ser declarada tanto em
VERTEX TABLES quanto em EDGE TABLES usando aliases diferentes
- É possível usar
results como vértice result e reutilizar a mesma tabela com os seguintes aliases de aresta
results AS res_driver: conecta result a driver
results AS res_race: conecta result a race
results AS res_constr: conecta result a constructor
- Cada alias de aresta usa as colunas de chave primária e chave estrangeira já existentes em
results
- Não é necessário criar tabelas separadas como
results_driver, results_race e results_constructor, e os aliases não armazenam dados
- Uma tabela fato com três chaves estrangeiras não deve ser declarada como uma única aresta com múltiplos destinos, mas sim como três aliases de aresta, cada um com uma origem e um destino
- Essa abordagem usa três aliases declarativos sobre uma única tabela de base, em vez de três tabelas físicas ou views
Conflitos de nome e tipo de propriedades
- Se
PROPERTIES for omitido, o SQL/PGQ expõe todas as colunas da tabela como propriedades
- Se
results e qualifying tiverem ambas uma coluna number, mas com tipos double precision e bigint, ocorrerá o seguinte erro
ERROR: property "number" data type mismatch: double precision vs. bigint
- Em todo o grafo, propriedades com o mesmo nome precisam ter um único tipo, então colunas homônimas com tipos diferentes entram em conflito
- Ao especificar apenas as colunas necessárias em
PROPERTIES, é possível excluir do grafo as colunas conflitantes
- Tanto o problema de chaves não virarem propriedades automaticamente quanto os conflitos de tipo podem ser resolvidos com uma lista explícita de propriedades permitidas
Consultas adequadas e inadequadas
-
Padrões relacionais fixos
- Grafos de propriedades são adequados para perguntas do tipo “encontre os alvos conectados a X por este padrão específico”
- No grafo de Fórmula 1, é possível escrever consultas como
- descobrir por quais constructors um driver correu
- encontrar competidores seguindo um padrão que vai de driver para result e race, depois para outro result e outro driver
- filtrar ao mesmo tempo estrutura e condições de propriedade, como resultados em que a posição de largada foi pior que 10 e o driver era italiano
- Quando o formato do relacionamento é conhecido de antemão e a estrutura é fixa e finita, a sintaxe de busca, filtro e agregação fica mais legível do que em joins relacionais
- Até consultas que exigiriam vários self-joins podem ser expressas de forma mais clara em um único padrão
MATCH
-
Problemas em que o caminho em si é desconhecido
- Os casos abaixo não se encaixam bem nos grafos de propriedades do Postgres 19
- o menor caminho entre dois drivers
- todos os alvos alcançáveis em até N saltos
- busca de conectividade cuja profundidade não é conhecida previamente
- Essas consultas exigem travessias de comprimento variável, então é preciso usar CTE recursiva sobre as tabelas de base
- Algoritmos de grafo como PageRank, detecção de comunidades e cálculo de centralidade também são um problema diferente de correspondência de padrões e, por isso, não fazem parte do escopo desse recurso
- O grafo de propriedades encontra entidades conectadas quando a estrutura do caminho é conhecida, mas não descobre caminhos quando não se sabe como X e Y estão conectados, nem calcula a importância estrutural do grafo
O que avaliar antes de adotar
- SQL/PGQ é um overlay declarativo sobre a estrutura existente de chaves estrangeiras e, a menos que você escolha o contrário, não armazena dados adicionais
- Há dois benefícios principais
- escrever travessias de forma fixa com mais legibilidade do que joins relacionais
- fornecer um objeto nomeado que documenta o esquema como grafo
- A maior limitação é a ausência de caminhos de comprimento variável, o que obriga a tratar buscas profundas ou abertas com SQL recursivo
- As tabelas em si não são inerentemente vértices nem arestas; em cada grafo, você decide se aquelas linhas serão lidas como vértices, arestas ou ambos
- Se a intenção for consultar padrões fixos de grafo sobre um esquema existente no Postgres 19, vale avaliar
CREATE PROPERTY GRAPH e MATCH antes de mover os dados para um banco de grafos separado
- Se for preciso explorar profundidades desconhecidas, será necessária uma CTE recursiva, mas em qualquer abordagem os dados não precisam sair do Postgres
- Antes de adotar de fato, é preciso testar diretamente se o desempenho atende ao necessário
Ainda não há comentários.