Por que o PostgreSQL executa varredura sequencial na coluna indexada?


150

Exemplo muito simples - uma tabela, um índice, uma consulta:

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

me dá:

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

Por que NÃO realiza a verificação de índice? o que estou perdendo?

Respostas:


222

Se o SELECT retornar mais de aproximadamente 5 a 10% de todas as linhas da tabela, uma varredura seqüencial será muito mais rápida que uma varredura de índice.

Isso ocorre porque uma varredura de índice requer várias operações de E / S para cada linha (procure a linha no índice e recupere-a da pilha). Enquanto uma varredura seqüencial requer apenas um único pedido de veiculação para cada linha - ou até menos porque um bloco (página) no disco contém mais de uma linha, portanto, mais de uma linha pode ser buscada com uma única operação de E / S.

Btw: isso também é válido para outros DBMS - algumas otimizações como "varreduras somente de índice" são deixadas de lado (mas para um SELECT * é altamente improvável que esse DBMS opte por uma "varredura apenas de índice")


12
Os 5-10% dependem de algumas definições de configuração e do armazenamento dos dados. Não é um número difícil.
precisa

6
@Frank: é por isso que eu disse "aproximadamente" :) Mas obrigado por apontar isso
a_horse_with_no_name

5
Além disso, uma varredura seqüencial pode solicitar várias páginas da pilha de cada vez e solicitar ao kernel que busque o próximo bloco enquanto trabalha no atual - uma varredura de índice busca uma página de uma vez. (Uma varredura de bitmap compromete os dois, geralmente você aparece em um plano de consultas que não são seletivas o suficiente para uma varredura de índice, mas ainda não são tão seletivas a ponto de merecer uma varredura de tabela completa)
araqnid

4
A questão interessante é como o banco de dados sabe quantas linhas a consulta retornará sem fazer isso primeiro? Ele armazena estatísticas como o número de valores diferentes em relação ao tamanho da tabela em algum lugar?
Laurent Grégoire

7
@ LaurentGrégoire: sim, o banco de dados armazena estatísticas sobre o número de linhas e a distribuição de valores. Veja o manual para obter detalhes: postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name 10/10

13

Você analisou a tabela / banco de dados? E as estatísticas ? Quando existem muitos registros em que ano> 2009, uma varredura seqüencial pode ser mais rápida que uma varredura de índice.


0

Na varredura de índice, a cabeça de leitura salta de uma linha para outra 1000 vezes mais lenta que a leitura do próximo bloco físico (na varredura seqüencial).

Portanto, se o (número de registros a serem recuperados * 1000) for menor que o número total de registros, a verificação do índice funcionará melhor.


0

@a_horse_with_no_name explicou muito bem. Além disso, se você realmente deseja usar uma varredura de índice, geralmente deve usar intervalos limitados na cláusula where. por exemplo - ano> 2019 e ano <2020.

Muitas vezes as estatísticas não são atualizadas em uma tabela e pode não ser possível devido a restrições. Nesse caso, o otimizador não saberá quantas linhas deve levar no ano> 2019. Assim, ele seleciona uma varredura seqüencial em vez de conhecimento completo. Partições limitadas resolverão o problema na maioria das vezes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.