Tempos de carregamento longos para a página de resumo do usuário com banco de dados lento

Olá,

Estamos enfrentando tempos de carregamento enormes ao acessar a página de resumo de um usuário. Parece que o resumo demora mais para carregar quanto mais ativo o usuário é no nosso site. O que, sim, parece bastante óbvio, mas a diferença nos tempos de carregamento no nosso site é imensa.
Assim, carregar a página de resumo de um usuário “novo” (algumas semanas de atividade) leva cerca de 1 segundo, mas carregar a página de um usuário que tem atividade diária há anos leva até 30-40 segundos.

Verificamos o banco de dados e ficamos bastante impressionados com o tamanho da tabela topic_views (incluindo índices), que é de 62 GB.

Aqui estão as nossas 7 maiores tabelas:

relation total_size table_size index_size reltuples
topic_views 62 GB 17 GB 45 GB 399215000
posts 27 GB 22 GB 5022 MB 9123860
top_topics 15 GB 708 MB 15 GB 1602180
post_search_data 15 GB 12 GB 2849 MB 8181010
incoming_links 12 GB 5330 MB 6647 MB 90008900
user_actions 3184 MB 877 MB 2307 MB 11872800
topics 2117 MB 1035 MB 1082 MB 1613070

Para testar isso, escolhemos um ID de usuário que sabemos ter um tempo de carregamento enorme nos resumos e executamos um count com esse ID na tabela topic_views. Essa consulta levou quase o mesmo tempo que o resumo do usuário levou para carregar. Portanto, a parte tópicos visualizados é responsável por esse atraso.

Como explicado em tópicos anteriores, atualizamos um site antigo baseado no Discourse (v1.2.4 + modificações) para a v2.4.0-beta.2 e agora estamos executando o Discourse v2.4.0-beta6. Então, pode haver alguns dados remanescentes. Mas não sabemos o que pode ser excluído.

Neste ponto, estamos bastante inseguros sobre o que fazer ou ajustar a seguir. Nossa instalação está rodando completamente no Azure, usando uma instância externa do Azure Database for PostgreSQL, e aplicamos a configuração descrita no seu postgres.10.template.yml. Nem sabemos se o tamanho da tabela topic_views (especialmente o índice) é “grande demais” em relação às outras tabelas ou se é bastante normal.

Qualquer dica, pensamento ou ideia é muito apreciada.

Cordiais saudações,
Sascha Hofmann

P.S.
Esqueci de mencionar que, por causa disso, temos vários erros 502 (exibidos no próprio site, então não é uma página de erro do nginx ou do gateway de aplicação) ao carregar /u/<username>/summary.json.

Você está visualizando como administrador / equipe ou como anônimo? A visualização da equipe é muito mais cara.

Não faz diferença se estou visualizando /u/<username>/summary como administrador/equipe ou com minha conta de usuário normal. Também temos a opção ‘ocultar perfis de usuários do público’ ativada, então os perfis dos usuários não são visíveis para anônimos (desativei para teste, mas não faz diferença, já que ‘tópicos visualizados’ também está presente no resumo).

Você migrou, modificou ou reconstruiu o mesmo banco de dados repetidamente? É possível que seu banco de dados precise de um VACUUM para atualizar as estatísticas. Consultas de 30 segundos estão muito fora da faixa normal que vemos em instalações do Discourse (embora admitamos que seu banco de dados seja grande).

VACUUM FULL vale a pena tentar se você puder aceitar algum tempo de inatividade.

Além disso, seu banco de dados está em armazenamento SSD rápido com MUITA RAM? Isso é crítico.

Para saber exatamente qual é o problema:

  1. Edite o arquivo app.yml e adicione seu e-mail de usuário administrador em DISCOURSE_DEVELOPER_EMAILS.

  2. Reconstrua

  3. Carregue a página lenta enquanto estiver logado como o usuário definido no passo 1.

  4. Compartilhe o resultado do mini-profiler

Compartilhe o conteúdo desta e da janela expandida:

Testamos várias vezes, mas sempre com uma cópia fresca do conjunto de dados antigo. Após algumas semanas e assim que nos certificamos de que havíamos revertido com sucesso as alterações do proprietário anterior, executamos a atualização e a migração uma única vez.

Isso definitivamente vale a pena tentar, mas não tenho certeza de quanto tempo isso levará. Mas sim, devemos considerar um vacuum completo. Especialmente porque tivemos alguns problemas com o banco de dados mais antigo .

Sim. Todos os dados são armazenados em um SSD de servidor e suportados por 40 GB de RAM (dos quais ~60% são usados no total, sem atingir platôs de 100% sob cargas mais altas).

Obrigado por este conselho, vou tentar.
Como usamos nossa própria imagem Docker, onde o app.yml está ausente, devemos obter o mesmo comportamento adicionando o(s) endereço(s) de e-mail ao developer_emails no discourse.conf.

Você pode acessar o console do Rails e usar Developers.create!(user_id: 123), onde 123 é o seu ID de usuário.

Infelizmente não está funcionando (sim, eu substituí o 123 antes :slight_smile:) :

discourse@2d5c3bf04550:~$ rails console --environment=production
Loading production environment (Rails 6.0.0)
irb(main):001:0> Developers.create!(user_id: 123)
Traceback (most recent call last):
        1: from (irb):1
NameError (uninitialized constant Developers)

Outra abordagem:

discourse@2d5c3bf04550:~$ rails runner --environment=production make_me_dev.rb
Traceback (most recent call last):
/var/www/discourse/bin/rails: Bootsnap::LoadPathCache::FallbackScan
	19: from /var/www/discourse/bin/rails:17:in `<main>'
	18: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require'
	17: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency'
	16: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require'
	15: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	14: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
	13: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	12: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
	11: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
	10: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands.rb:18:in `<main>'
	 9: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/command.rb:46:in `invoke'
	 8: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/command/base.rb:65:in `perform'
	 7: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-0.20.3/lib/thor.rb:387:in `dispatch'
	 6: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command'
	 5: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/thor-0.20.3/lib/thor/command.rb:27:in `run'
	 4: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands/runner/runner_command.rb:42:in `perform'
	 3: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:52:in `load'
	 2: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:69:in `rescue in load'
	 1: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:69:in `load'
make_me_dev.rb:1:in `<main>': uninitialized constant Developers (NameError)
discourse@2d5c3bf04550:~$ cat make_me_dev.rb
Developers.create!(user_id: 123)

Vou tentar o caminho do discourse.conf e fornecer os dados solicitados assim que possível.

Obrigado pelas suas dicas até agora!

Bem, é por isso que sempre dizemos às pessoas para usarem o método oficial e suportado de instalar o Discourse. Assim, quando for necessário ajuda, podemos auxiliar utilizando ferramentas padrão.

Sim, talvez seja porque estamos usando o supervisord para iniciar todos os processos.

De qualquer forma, aqui está a saída que você solicitou (conteúdo HTML compactado):
_u_x_strom_summary.json-13498.2ms-ProfilingResults.zip (94,5 KB)

Essa solicitação levou 13 segundos, mas precisei carregar o site duas vezes. Novamente, a primeira tentativa demorou demais e resultou em um erro 502. Talvez algumas coisas já estivessem em cache.

Levou mais de 13 segundos para executar 51 consultas SQL. Seu banco de dados está seriamente mal configurado ou com capacidade insuficiente.

Maiores culpados
SELECT "posts"."id" AS t0_r0, "posts"."user_id" AS t0_r1, "posts"."topic_id" AS t0_r2, "posts"."post_number" AS t0_r3, "posts"."raw" AS t0_r4, "posts"."cooked" AS t0_r5, "posts"."created_at" AS t0_r6, "posts"."updated_at" AS t0_r7, "posts"."reply_to_post_number" AS t0_r8, "posts"."reply_count" AS t0_r9, "posts"."quote_count" AS t0_r10, "posts"."deleted_at" AS t0_r11, "posts"."off_topic_count" AS t0_r12, "posts"."like_count" AS t0_r13, "posts"."incoming_link_count" AS t0_r14, "posts"."bookmark_count" AS t0_r15, "posts"."avg_time" AS t0_r16, "posts"."score" AS t0_r17, "posts"."reads" AS t0_r18, "posts"."post_type" AS t0_r19, "posts"."sort_order" AS t0_r20, "posts"."last_editor_id" AS t0_r21, "posts"."hidden" AS t0_r22, "posts"."hidden_reason_id" AS t0_r23, "posts"."notify_moderators_count" AS t0_r24, "posts"."spam_count" AS t0_r25, "posts"."illegal_count" AS t0_r26, "posts"."inappropriate_count" AS t0_r27, "posts"."last_version_at" AS t0_r28, "posts"."user_deleted" AS t0_r29, "posts"."reply_to_user_id" AS t0_r30, "posts"."percent_rank" AS t0_r31, "posts"."notify_user_count" AS t0_r32, "posts"."like_score" AS t0_r33, "posts"."deleted_by_id" AS t0_r34, "posts"."edit_reason" AS t0_r35, "posts"."word_count" AS t0_r36, "posts"."version" AS t0_r37, "posts"."cook_method" AS t0_r38, "posts"."wiki" AS t0_r39, "posts"."baked_at" AS t0_r40, "posts"."baked_version" AS t0_r41, "posts"."hidden_at" AS t0_r42, "posts"."self_edits" AS t0_r43, "posts"."reply_quoted" AS t0_r44, "posts"."via_email" AS t0_r45, "posts"."raw_email" AS t0_r46, "posts"."public_version" AS t0_r47, "posts"."action_code" AS t0_r48, "posts"."image_url" AS t0_r49, "posts"."locked_by_id" AS t0_r50, "topics"."id" AS t1_r0, "topics"."title" AS t1_r1, "topics"."last_posted_at" AS t1_r2, "topics"."created_at" AS t1_r3, "topics"."updated_at" AS t1_r4, "topics"."views" AS t1_r5, "topics"."posts_count" AS t1_r6, "topics"."user_id" AS t1_r7, "topics"."last_post_user_id" AS t1_r8, "topics"."reply_count" AS t1_r9, "topics"."featured_user1_id" AS t1_r10, "topics"."featured_user2_id" AS t1_r11, "topics"."featured_user3_id" AS t1_r12, "topics"."avg_time" AS t1_r13, "topics"."deleted_at" AS t1_r14, "topics"."highest_post_number" AS t1_r15, "topics"."image_url" AS t1_r16, "topics"."like_count" AS t1_r17, "topics"."incoming_link_count" AS t1_r18, "topics"."category_id" AS t1_r19, "topics"."visible" AS t1_r20, "topics"."moderator_posts_count" AS t1_r21, "topics"."closed" AS t1_r22, "topics"."archived" AS t1_r23, "topics"."bumped_at" AS t1_r24, "topics"."has_summary" AS t1_r25, "topics"."archetype" AS t1_r26, "topics"."featured_user4_id" AS t1_r27, "topics"."notify_moderators_count" AS t1_r28, "topics"."spam_count" AS t1_r29, "topics"."pinned_at" AS t1_r30, "topics"."score" AS t1_r31, "topics"."percent_rank" AS t1_r32, "topics"."subtype" AS t1_r33, "topics"."slug" AS t1_r34, "topics"."deleted_by_id" AS t1_r35, "topics"."participant_count" AS t1_r36, "topics"."word_count" AS t1_r37, "topics"."excerpt" AS t1_r38, "topics"."pinned_globally" AS t1_r39, "topics"."pinned_until" AS t1_r40, "topics"."fancy_title" AS t1_r41, "topics"."highest_staff_post_number" AS t1_r42, "topics"."featured_link" AS t1_r43, "topics"."reviewable_score" AS t1_r44 FROM "posts" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "posts"."topic_id" WHERE ("posts"."deleted_at" IS NULL) AND (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "posts"."user_id" = 643476 AND (post_number > 1) ORDER BY posts.like_count DESC, posts.created_at DESC LIMIT 6; 

Demorou 6248,3 ms

SELECT "topic_links"."id" AS t0_r0, "topic_links"."topic_id" AS t0_r1, "topic_links"."post_id" AS t0_r2, "topic_links"."user_id" AS t0_r3, "topic_links"."url" AS t0_r4, "topic_links"."domain" AS t0_r5, "topic_links"."internal" AS t0_r6, "topic_links"."link_topic_id" AS t0_r7, "topic_links"."created_at" AS t0_r8, "topic_links"."updated_at" AS t0_r9, "topic_links"."reflection" AS t0_r10, "topic_links"."clicks" AS t0_r11, "topic_links"."link_post_id" AS t0_r12, "topic_links"."title" AS t0_r13, "topic_links"."crawled_at" AS t0_r14, "topic_links"."quote" AS t0_r15, "topic_links"."extension" AS t0_r16, "topics"."id" AS t1_r0, "topics"."title" AS t1_r1, "topics"."last_posted_at" AS t1_r2, "topics"."created_at" AS t1_r3, "topics"."updated_at" AS t1_r4, "topics"."views" AS t1_r5, "topics"."posts_count" AS t1_r6, "topics"."user_id" AS t1_r7, "topics"."last_post_user_id" AS t1_r8, "topics"."reply_count" AS t1_r9, "topics"."featured_user1_id" AS t1_r10, "topics"."featured_user2_id" AS t1_r11, "topics"."featured_user3_id" AS t1_r12, "topics"."avg_time" AS t1_r13, "topics"."deleted_at" AS t1_r14, "topics"."highest_post_number" AS t1_r15, "topics"."image_url" AS t1_r16, "topics"."like_count" AS t1_r17, "topics"."incoming_link_count" AS t1_r18, "topics"."category_id" AS t1_r19, "topics"."visible" AS t1_r20, "topics"."moderator_posts_count" AS t1_r21, "topics"."closed" AS t1_r22, "topics"."archived" AS t1_r23, "topics"."bumped_at" AS t1_r24, "topics"."has_summary" AS t1_r25, "topics"."archetype" AS t1_r26, "topics"."featured_user4_id" AS t1_r27, "topics"."notify_moderators_count" AS t1_r28, "topics"."spam_count" AS t1_r29, "topics"."pinned_at" AS t1_r30, "topics"."score" AS t1_r31, "topics"."percent_rank" AS t1_r32, "topics"."subtype" AS t1_r33, "topics"."slug" AS t1_r34, "topics"."deleted_by_id" AS t1_r35, "topics"."participant_count" AS t1_r36, "topics"."word_count" AS t1_r37, "topics"."excerpt" AS t1_r38, "topics"."pinned_globally" AS t1_r39, "topics"."pinned_until" AS t1_r40, "topics"."fancy_title" AS t1_r41, "topics"."highest_staff_post_number" AS t1_r42, "topics"."featured_link" AS t1_r43, "topics"."reviewable_score" AS t1_r44, "posts"."id" AS t2_r0, "posts"."user_id" AS t2_r1, "posts"."topic_id" AS t2_r2, "posts"."post_number" AS t2_r3, "posts"."raw" AS t2_r4, "posts"."cooked" AS t2_r5, "posts"."created_at" AS t2_r6, "posts"."updated_at" AS t2_r7, "posts"."reply_to_post_number" AS t2_r8, "posts"."reply_count" AS t2_r9, "posts"."quote_count" AS t2_r10, "posts"."deleted_at" AS t2_r11, "posts"."off_topic_count" AS t2_r12, "posts"."like_count" AS t2_r13, "posts"."incoming_link_count" AS t2_r14, "posts"."bookmark_count" AS t2_r15, "posts"."avg_time" AS t2_r16, "posts"."score" AS t2_r17, "posts"."reads" AS t2_r18, "posts"."post_type" AS t2_r19, "posts"."sort_order" AS t2_r20, "posts"."last_editor_id" AS t2_r21, "posts"."hidden" AS t2_r22, "posts"."hidden_reason_id" AS t2_r23, "posts"."notify_moderators_count" AS t2_r24, "posts"."spam_count" AS t2_r25, "posts"."illegal_count" AS t2_r26, "posts"."inappropriate_count" AS t2_r27, "posts"."last_version_at" AS t2_r28, "posts"."user_deleted" AS t2_r29, "posts"."reply_to_user_id" AS t2_r30, "posts"."percent_rank" AS t2_r31, "posts"."notify_user_count" AS t2_r32, "posts"."like_score" AS t2_r33, "posts"."deleted_by_id" AS t2_r34, "posts"."edit_reason" AS t2_r35, "posts"."word_count" AS t2_r36, "posts"."version" AS t2_r37, "posts"."cook_method" AS t2_r38, "posts"."wiki" AS t2_r39, "posts"."baked_at" AS t2_r40, "posts"."baked_version" AS t2_r41, "posts"."hidden_at" AS t2_r42, "posts"."self_edits" AS t2_r43, "posts"."reply_quoted" AS t2_r44, "posts"."via_email" AS t2_r45, "posts"."raw_email" AS t2_r46, "posts"."public_version" AS t2_r47, "posts"."action_code" AS t2_r48, "posts"."image_url" AS t2_r49, "posts"."locked_by_id" AS t2_r50 FROM "topic_links" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "topic_links"."topic_id" INNER JOIN "posts" ON ("posts"."deleted_at" IS NULL) AND "posts"."id" = "topic_links"."post_id" WHERE (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "topic_links"."user_id" = 643476 AND "topic_links"."internal" = FALSE AND "topic_links"."reflection" = FALSE AND "topic_links"."quote" = FALSE ORDER BY clicks DESC, topic_links.created_at DESC LIMIT 6; 

Demorou 258,3 ms

SELECT acting_user_id, COUNT(*) FROM "user_actions" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "user_actions"."target_topic_id" INNER JOIN "posts" ON ("posts"."deleted_at" IS NULL) AND "posts"."id" = "user_actions"."target_post_id" WHERE ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "user_actions"."user_id" = 643476 AND "user_actions"."action_type" = 2 GROUP BY "user_actions"."acting_user_id" ORDER BY COUNT(*) DESC LIMIT 6; 

Demorou 245,5 ms

SELECT user_actions.user_id, COUNT(*) FROM "user_actions" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "user_actions"."target_topic_id" INNER JOIN "posts" ON ("posts"."deleted_at" IS NULL) AND "posts"."id" = "user_actions"."target_post_id" WHERE ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "user_actions"."action_type" = 2 AND "user_actions"."acting_user_id" = 643476 GROUP BY "user_actions"."user_id" ORDER BY COUNT(*) DESC LIMIT 6; 

Demorou 277,2 ms

SELECT replies.user_id, COUNT(*) FROM "posts" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "posts"."topic_id" JOIN posts replies ON posts.topic_id = replies.topic_id AND posts.reply_to_post_number = replies.post_number WHERE ("posts"."deleted_at" IS NULL) AND (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "posts"."user_id" = 643476 AND (replies.user_id <> 643476) GROUP BY replies.user_id ORDER BY COUNT(*) DESC LIMIT 6; 

Demorou 3064,6 ms

SELECT category_id FROM "posts" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "posts"."topic_id" WHERE ("posts"."deleted_at" IS NULL) AND (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "posts"."user_id" = 643476 GROUP BY topics.category_id ORDER BY COUNT(*) DESC LIMIT 6; 

Demorou 2283,3 ms

SELECT category_id, COUNT(*) FROM "posts" INNER JOIN "topics" ON ("topics"."deleted_at" IS NULL) AND "topics"."id" = "posts"."topic_id" WHERE ("posts"."deleted_at" IS NULL) AND (posts.post_type IN (1,2,3,4)) AND ("topics"."deleted_at" IS NULL) AND (topics.archetype <> 'private_message') AND "topics"."visible" = TRUE AND (topics.category_id IS NULL OR topics.category_id IN (SELECT id FROM categories WHERE NOT read_restricted OR id IN (1,3,6,100,141,202,229,233,235,248,262,594,595,609))) AND "posts"."user_id" = 643476 AND (post_number > 1) AND (topics.category_id in (64,13,59,124,327,122)) GROUP BY topics.category_id ORDER BY COUNT(*) DESC; 

Demorou 811,5 ms

Acredito que o Azure tenha algum tipo de estatística de banco de dados para o serviço hospedado; você precisa verificar essas estatísticas e avaliar o que precisa ser alterado.

Além disso, verifique a URL /sidekiq na sua instalação para ver se não há contenção de fila mantendo o banco de dados ocupado.

Foi exatamente isso que verificamos primeiro. Nossa instância possui:

  • 8 núcleos (~16,18% de utilização, com picos de 60%)
  • 40 GB de RAM (~60% utilizados, sem picos)
  • 2244 IOPS disponíveis (~2,5% de utilização, com picos de 24%)

Como dito, utilizamos a configuração descrita no seu postgres.10.template.yml. Todo o resto está com as configurações padrão. Parece que devemos dar outra olhada nisso.

O Sidekiq está apresentando bons resultados no momento. 0 ocupado, 0 enfileirado, 0 repetições, 1 agendado, 0 morto. A lista de tarefas está atualmente vazia.

Portanto, para chegar a uma primeira conclusão: inicialmente, verificaremos a configuração do PostgreSQL, pois há algumas otimizações que podemos aplicar. Se não funcionar, devemos considerar a atualização da instância do PostgreSQL e/ou realizar um vacuum completo.

Obrigado pelo seu tempo até agora e tenha um ótimo fim de semana!
Atenciosamente,
Sascha

Se você tiver 40 GB de RAM na máquina, as configurações padrão em postgres.10.template.yml não são mais adequadas, conforme destacado em samples/standalone.yml:

Olá,

Obrigado pela sua resposta. Existem algumas limitações ao usar uma instância do PostgreSQL no Azure. Não é possível definir algumas configurações, como effective_cache_size, max_connections, maintenance_worker_mem ou shared_buffers.
No momento em que escrevemos este chamado de suporte, estávamos usando o nível “General Purpose”, que nos fornecia 40 GB de RAM, mas apenas 1 GB de shared_buffers e 2,5 GB de effective_cache_size.
Desde ontem, mudamos para o nível “Memory Optimized”, o que dobrou a RAM para 80 GB, com 2 GB de shared_buffers e 5 GB de effective_cache_size.
O work_mem, que é uma configuração que podemos ajustar, está atualmente definido como 128 MB, pois não há entradas de temporary file em nossos logs.

O interessante foi que, assim que mudamos o nível, o uso de CPU e IOPS caiu, sem aumentar os vCores ou o armazenamento. Isso confirma que tínhamos um problema causado por caches e buffers muito pequenos.

Ainda temos tempos de carregamento longos ao exibir páginas de resumo de alguns usuários (especialmente usuários da equipe ou usuários de longa data) ou a página about, mas está bem melhor do que antes (cerca de 50% dos tempos de carregamento anteriores).

Atenciosamente,

P.S.
Para quem enfrenta problemas semelhantes e tem mais controle sobre sua instalação do PostgreSQL, estas pequenas guias podem ser úteis:

Architecture and Tuning of Memory in PostgreSQL Databases | Severalnines

Bom saber. Os próximos passos seriam ver se você consegue usar um vCPU de 4 núcleos otimizado para memória como uma otimização de preço ou migrar para executá-lo você mesmo.

Ah, estamos rodando 8 vCores, o que resulta em 80 GB de RAM. O shared_buffers está configurado em 2 GB, mas deveria estar em 16 GB para esse nível e contagem de vCore. No entanto, já estamos em contato com o Suporte do Azure para corrigir isso.

P.S.
Já estamos com o shared_buffers em 16 GB. Eu interpretei mal a saída de SELECT * FROM pg_settings WHERE name = 'shared_buffers';. A unidade é 8kb.

Então, acho que esse tópico pode ser fechado. Agradeço a todos pelo empenho e espero que possamos alcançar um desempenho melhor nos próximos dias, junto com o suporte do Azure.

P.P.S.
Desculpe, @riking, eu te entendi mal. Acredito que estamos bem com 8 vCores em vez de reduzir para 4. Podemos tentar assim que alcançarmos o desempenho que buscamos.