AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 210136
Accepted
Imanol Y.
Imanol Y.
Asked: 2018-06-21 04:33:36 +0800 CST2018-06-21 04:33:36 +0800 CST 2018-06-21 04:33:36 +0800 CST

Como otimizar uma consulta para < operador

  • 772

Tenho um SELECTque fica muito lento ao usar o <operador procuro correções ou soluções alternativas para realizar esta operação:

EXPLAIN (ANALYZE) 
SELECT * 
FROM "users" 
WHERE (engagement_level(social) < 1) 
    AND (social_peemv(social) < 33.333333333333336) 
    AND (array['United Kingdom'] <@ mixed_frequent_locations(location)) 
    AND (is_visible(social, flags) = TRUE) 
ORDER BY "users"."created_at" ASC 
LIMIT 12 OFFSET 0;
                                                                                                               QUERY PLAN

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------    ---------------------------
 Limit  (cost=0.43..18572.10 rows=12 width=860) (actual time=5658.037..175582.743 rows=12 loops=1)
   ->  Index Scan using created_at_idx on users  (cost=0.43..6244724.16 rows=4035 width=860) (actual time=5658.035..175582.735 rows=12 loops=1)
         Filter: (is_visible(social, flags) AND (engagement_level(social) < 1) AND (social_peemv(social) < '33.3333333333333'::double precision) AND ('{"United Kingdom"}'::text[] <@ mixed_frequent_locations(location)))
         Rows Removed by Filter: 2816798
 Planning time: 1.573 ms
 Execution time: 175583.373 ms
(6 rows)
EXPLAIN (ANALYZE) 
SELECT * 
FROM "users" 
WHERE (engagement_level(social) < 1) 
  AND (social_peemv(social) = 33.3333) 
  AND (array['United Kingdom'] <@ mixed_frequent_locations(location)) 
  AND (is_visible(social, flags) = TRUE)
ORDER BY "users"."created_at" ASC
LIMIT 12 OFFSET 0;
                                                                                QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=380.04..380.31 rows=1 width=863) (actual time=0.051..0.051 rows=0 loops=1)
   ->  Result  (cost=380.04..380.31 rows=1 width=863) (actual time=0.050..0.050 rows=0 loops=1)
         ->  Sort  (cost=380.04..380.05 rows=1 width=896) (actual time=0.049..0.049 rows=0 loops=1)
               Sort Key: created_at
               Sort Method: quicksort  Memory: 25kB
               ->  Index Scan using idx_in_social_peemv on users  (cost=0.43..380.03 rows=1 width=896) (actual time=0.044..0.044 rows=0 loops=1)
                     Index Cond: (social_peemv(social) = '33.3333'::double precision)
                     Filter: (is_visible(social, flags) AND (engagement_level(social) < 1) AND ('{"United Kingdom"}'::text[] <@ mixed_frequent_locations(location)))
 Planning time: 0.459 ms
 Execution time: 0.095 ms

No primeiro caso não Index Condé aplicado e o tempo de execução cresce para175583.373 ms

O índice:

 CREATE INDEX idx_in_social_peemv ON users USING BTREE ( social_peemv(social) ) ;
 CREATE INDEX mixed_frequent_locations_idx on users USING GIN ( mixed_frequent_locations(location) ) ;
 CREATE INDEX created_at_idx ON users USING btree (created_at)
 CREATE INDEX idx_in_social_follower_count_and_created_at ON users USING btree (social_follower_count(social) DESC, created_at)
 CREATE INDEX idx_in_egagagement_level_and_created_at ON users USING btree (engagement_level(social), creat
ed_at)

A mesa:

CREATE TABLE users (
    id SERIAL PRIMARY KEY NOT NULL,
    name TEXT,
    bio TEXT,
    social jsonb,
    flags array,
    location jsonb,
    search_field ts_vector,
    created_at TIMESTAMP WITHOUT TIMEZONE,
    udpated_at TIMESTAMP WITHOUT TIMEZONE
);

Versão do Postgres: 10

Toda a condição corresponde a 20 registros de um total de 3669284

Cada condição corresponde:

(engagement_level(social) < 1)= 801176

(social_peemv(social) < 33.333333333333336)= 1621516

(array['United Kingdom'] <@ mixed_frequent_locations(location))= 91625

(is_visible(social, flags) = TRUE)= 3333733

Como sugerido por @jjanes, tentei remover o LIMITe OFFSETe o plano de consulta mudou para um BitMap Heap Scan:

EXPLAIN (ANALYZE)
SELECT *
FROM "users"
WHERE (engagement_level(social) < 1)
     AND (social_peemv(social) < 33.333333333333336)
     AND (array['United Kingdom'] <@ mixed_frequent_locations(location))
     AND (is_visible(social, flags) = TRUE)
ORDER BY "users"."created_at" ASC;
                                                                                  QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=77641.99..77652.36 rows=4148 width=1393) (actual time=1195.544..1195.546 rows=20 loops=1)
   Sort Key: created_at
   Sort Method: quicksort  Memory: 59kB
   ->  Bitmap Heap Scan on users  (cost=18046.48..77392.73 rows=4148 width=1393) (actual time=227.471..1195.481 rows=20 loops=1)
         Recheck Cond: (('{"United Kingdom"}'::text[] <@ mixed_frequent_locations(location)) AND (engagement_level(social) < 1))
         Filter: (is_visible(social, flags) AND (social_peemv(social) < '33.3333333333333'::double precision))
         Rows Removed by Filter: 19444
         Heap Blocks: exact=19238
         ->  BitmapAnd  (cost=18046.48..18046.48 rows=28415 width=0) (actual time=218.484..218.484 rows=0 loops=1)
               ->  Bitmap Index Scan on mixed_frequent_locations_idx  (cost=0.00..1356.36 rows=128634 width=0) (actual time=44.794..44.794 rows=108076 loops=1)
                     Index Cond: ('{"United Kingdom"}'::text[] <@ mixed_frequent_locations(location))
               ->  Bitmap Index Scan on idx_in_egagagement_level_and_created_at  (cost=0.00..16687.80 rows=1156662 width=0) (actual time=163.368..163.368 rows=801189 loops=1)
                     Index Cond: (engagement_level(social) < 1)
 Planning time: 3.326 ms
 Execution time: 1197.242 ms

Todas as condições aplicadas, exceto as is_visible, são dadas pelo usuário

postgresql optimization
  • 2 2 respostas
  • 113 Views

2 respostas

  • Voted
  1. Best Answer
    jjanes
    2018-06-22T09:23:15+08:002018-06-22T09:23:15+08:00

    Você tem um problema clássico de dependência de coluna. O PostgreSQL acredita que haverá 4.035 linhas que atendem à cláusula WHERE com base em estimativas. Se eu pegar as seletividades reais que você relatou e multiplicá-las (o que é correto apenas se cada uma for independente das outras), obterei 8032 linhas. Mas o verdadeiro valor é 20. Aparentemente, as pessoas do Reino Unido são anormalmente anti-sociais, ou algo assim.

    Com o LIMIT 12, ele pensa que apenas percorrerá o índice na mesma ordem do ORDER BY e parará quando encontrar 12 linhas que passem pelos filtros. Ele acha que precisará andar apenas cerca de 12/4035 do índice. Mas ele realmente precisa andar cerca de 12/20 do índice (a menos que também haja uma correlação entre a data de criação e a socialidade, então mesmo essas estimativas estariam erradas). Então ele escolhe esses métodos porque acha que eles serão mais rápidos.

    Nas versões mais recentes do PostgreSQL, você pode coletar estatísticas sobre dependências entre colunas, mas não pode fazer isso em funções/expressões, então não funcionaria para você. Eu não acho que funcionaria para colunas de matriz, de qualquer maneira.

    Se seus cortes fossem codificados, você poderia criar um índice parcial como o abaixo, mas parece que isso também não funcionará para você, a menos que você esteja disposto a comprometer isso.

    CREATE INDEX mixed_frequent_locations_idx_2 on users 
      USING GIN ( mixed_frequent_locations(location) )
      WHERE (engagement_level(social) < 1)
       AND (social_peemv(social) < 33.333333333333336)
       AND (is_visible(social, flags) = TRUE) ;
    

    Muitas vezes, você pode resolver o problema criando um índice de várias colunas com apenas a ordem certa de colunas, o que é tão bom para a consulta que é usado mesmo se as estimativas de seletividade estiverem longe. Mas uma vez que todas as condições seletivas são baseadas em desigualdade ou associação de matriz, não é óbvio como você poderia chegar a esse índice. É possível que você possa usar um índice GiST para isso. btree_gistfornece classes de operadores GiST para '<' nos números, mas não conheço nada que forneça suporte <@ em matrizes de strings. Você pode tentar um índice, USING GIST ON (engagement_level(social), social_peemv(social))mas como a maior parte de sua seletividade vem, mixed_frequent_locations(location)eu não teria grandes esperanças de que um índice sem isso funcionasse bem o suficiente para parecer melhor do que o plano ORDER BY indexado existente.

    Coloque tudo junto, e eu não acho que você tenha muitas ótimas opções aqui. Procurar seletivamente as consultas de problemas e remover seu LIMIT é provavelmente a melhor opção, por mais desagradável que seja. Em vez de remover o LIMIT, você pode apenas especificar o ORDER BY assim:

    ORDER BY "users"."created_at" + '0 seconds'::interval ASC
    

    Isso impedirá que o índice falsamente atraente seja usado, sem alterar a saída das consultas.

    • 1
  2. Evan Carroll
    2018-06-21T23:04:48+08:002018-06-21T23:04:48+08:00

    Na consulta rápida, você está retornando 0 linhas. Isso é fácil. O PostgreSQL vê social_peemv(social)e tem uma estimativa estatística suculenta para ele e faz a varredura idx_in_social_peemv. Ele retorna 0 linhas e a consulta é feita.

    No outro você está dizendo < 33.333333333333336. Como isso significa quase metade da tabela, o PostgreSQL descobre que o valor não vale o custo de acordo com as estimativas de seletividade. Em vez disso, ele verifica um índice diferente e remove 2816798 linhas de seu conjunto de resultados.

    Ainda não sabemos o que suas funções estão fazendo e não temos a definição da tabela. Você também não nos deu todos os índices created_at_idx.

    • 0

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve