4.3. Árvores-R no PostgreSQL com PostGIS
O PostGIS implementa uma Árvore-R sobre o GiST do PostgreSQL. Para criar um índice espacial associado a uma coluna geométrica, podemos usar o comando CREATE INDEX
com seguinte sintaxe:
CREATE INDEX <nome-indice> ON <nome-tabela> USING GIST ( <coluna-geometrica> );
A opção USING GIST
indica que o método de indexação a ser usado na criação do índice deverá ser baseado no GiST. Desta forma, o índice criado será uma Árvore-R no caso do tipo GEOMETRY
do PostGIS.
O índice espacial baseado no GIST é importante para consultas envolvendo relacionamentos topológicos, como ST_Contains
, ST_Within
, ST_CoveredBy
, ST_Covers
, ST_Crosses
, ST_Equals
, ST_Overlaps
, ST_Touches e ST_Intersects
. Esses operadores na verdade utilizam automaticamente um teste entre os retângulos envolventes das geometrias antes de realizar um processamento completo dos vértices das duas geometrias. Nas consultas, o teste baseado em retângulo pode explorar o uso do índice espacial. Por isso , esses operadores topológicos são definidos da seguinte forma:
Assim como no caso do índice baseado em Árvore-B+, onde operadores como <
, >
, <=
, >=
e =
permitem explorar a existência de índices no processamento de uma consulta, com o tipo GEOMETRY
do PostGIS, também temos um conjunto de operadores que podem explorar a existência de um índice espacial. Os seguintes operadores podem ser usados pelo processador de consultas para explorar um índice espacial:
<<
: Em expressões comogeometria-1 << geometria-2
, o operador<<
retornaTRUE
se o retângulo envolvente dageometria-1
encontra-se completamente à esquerda do retângulo envolvente dageometria-2
.>>
: Em expressões comogeometria-1 >> geometria-2
, o operador>>
retornaTRUE
se o retângulo envolvente dageometria-1
encontra-se completamente à direita do retângulo envolvente dageometria-2
.<<|
: Em expressões comogeometria-1 <<| geometria-2
, o operador<<|
retornaTRUE
se o retângulo envolvente dageometria-1
encontra-se completamente abaixo do retângulo envolvente dageometria-2
.|>>
: Em expressões comogeometria-1 |>> geometria-2
, o operador|>>
retornaTRUE
se o retângulo envolvente dageometria-1
encontra-se completamente acima do retângulo envolvente dageometria-2
.&<
: Em expressões comogeometria-1 &< geometria-2
, o operador&<
retornaTRUE
se o retângulo envolvente dageometria-1
sobrepõem ou encontra-se à esquerda do retângulo envolvente dageometria-2
.&>
: Em expressões comogeometria-1 &> geometria-2
, o operador&>
retornaTRUE
se o retângulo envolvente dageometria-1
sobrepõem ou encontra-se à direita do retângulo envolvente dageometria-2
.&<
: Em expressões comogeometria-1 &<| geometria-2
, o operador&<
retornaTRUE
se o retângulo envolvente dageometria-1
sobrepõem ou encontra-se abaixo do retângulo envolvente dageometria-2
.|&>
: Em expressões comogeometria-1 |&> geometria-2
, o operador|&>
retornaTRUE
se o retângulo envolvente dageometria-1
sobrepõem ou encontra-se acima do retângulo envolvente dageometria-2
.&&
: Em expressões comogeometria-1 && geometria-2
, o operador&&
retornaTRUE
se o retângulo envolvente dageometria-1
intercepta o retângulo envolvente dageometria-2
. Isso significa que se os retângulos tiverem qualquer interação espacial, esse operador retornarTRUE
.@
: Em expressões comogeometria-1 @ geometria-2
, o operador@
retornaTRUE
se o retângulo envolvente dageometria-1
encontra-se completamente contido no retângulo envolvente dageometria-2
.~
: Em expressões comogeometria-1 ~ geometria-2
, o operador~
retornaTRUE
se o retângulo envolvente dageometria-1
contem completamente o retângulo envolvente dageometria-2
.~=
: Em expressões comogeometria-1 ~= geometria-2
, o operador~=
retornaTRUE
se o retângulo envolvente dageometria-1
é exatamente igual ao retângulo envolvente dageometria-2
.
Nota
A sintaxe acima cria um índice bidimensional. Para criar um índice \(n\text{-dimensional}\) para tipos geométricos 3D, com \(n > 2\), podemos utilizar a seguinte sintaxe:
CREATE INDEX <nome-indice> ON <nome-tabela> USING GIST (<coluna-geometrica> gist_geometry_ops_nd);
Dica
Ao criar um índice espacial, lembre-se de atualizar as estatísticas da tabela:
ANALYZE <nome-tabela>
ou:
VACUUM ANALYZE <nome-tabela>
Nota
Vamos ver a definição das tabelas com colunas geométricas importadas para o banco de dados.
4.3.1. Exercícios
Exercício 1. Vamos criar uma tabela chamada pts_pgis
com a seguinte definição:
CREATE TABLE pts_pgis
(
id UUID DEFAULT gen_random_uuid(),
geom GEOMETRY(POINT, 4326),
word TEXT
);
Em seguida, vamos inserir um conjunto sintético de dados nessa tabela:
INSERT INTO pts_pgis (geom, word)
(
SELECT ST_SetSRID(
ST_MakePoint(
360.0 * random() - 180.0,
180.0 * random() - 90.0
),
4326
),
rpad(i::text, 10) AS word
FROM generate_series(1, 1000000) AS i
);
Verifique como a seguinte consulta é realizada:
EXPLAIN ANALYZE
SELECT *
FROM pts_pgis
WHERE ST_Intersects( geom, ST_MakeEnvelope(1.0, 1.0, 2.0, 2.0, 4326) );
Exercício 2. Crie um índice espacial sobre a coluna geom
da tabela pts_pgis
:
CREATE INDEX pts_pgis_geom_idx ON pts_pgis USING GIST ( geom );
Em seguida, refaça as estatísticas sobre a tabela:
ANALYZE pts_pgis;
Analise novamente a consulta abaixo:
EXPLAIN ANALYZE
SELECT *
FROM pts_pgis
WHERE ST_Intersects( geom, ST_MakeEnvelope(1.0, 1.0, 2.0, 2.0, 4326) );