-
Notifications
You must be signed in to change notification settings - Fork 371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Altera os tipos de transações de conteúdos na tabela balance_operations
#1624
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
1f7561b
to
e1ec794
Compare
Eu tentei testar essa migração num banco que tenho com muitos dados e que estava usando para testar o desempenho do PR #1607, mas aquele teste de uma publicação com 27 comentários está demorando ~800ms (vs ~60ms) com a query que apenas pega o total de TabCoins ( Você tem ideia de qual é o problema? 🤔 Não sei se em homologação também está demorando mais. |
Local e homologação está normal. Nenhuma diferença perceptível na Faz o teste, por exemplo, qualificando qualquer conteúdo em homologação. Não importa qual deploy. Será que seu banco não estava ocupado, talvez atualizando o índice? Mesmo assim, 57s é muito tempo. Ele atualizou corretamente todos os |
Esse é o Também tive o problema criando um banco grande (porém bem menor) já na sua branch, ou seja, teoricamente está tudo certo. A query que eu estava testando é a do WITH parent AS (SELECT * FROM contents
WHERE
contents.owner_id = (
SELECT id FROM users
WHERE
LOWER(username) = LOWER('<username>')
LIMIT 1
)
AND
contents.slug = '<slug>' AND
contents.status = 'published'
)
SELECT
parent.*,
users.username as owner_username,
get_current_balance('content:tabcoin', parent.id) as tabcoins
FROM
parent
INNER JOIN
users ON parent.owner_id = users.id
UNION ALL
SELECT
c.*,
users.username as owner_username,
get_current_balance('content:tabcoin', c.id) as tabcoins
FROM
contents c
INNER JOIN
parent ON c.path @> ARRAY[parent.id]::uuid[]
INNER JOIN
users ON c.owner_id = users.id
WHERE
c.status = 'published'; O endpoint WITH content_window AS (
SELECT
COUNT(*) OVER()::INTEGER as total_rows,
id
FROM contents
WHERE contents.slug = '<slug>' AND contents.status = 'published' AND contents.owner_id = '<user-id>'
LIMIT 1 OFFSET 0
)
SELECT
contents.id,
contents.owner_id,
contents.parent_id,
contents.slug,
contents.title,
contents.body,
contents.status,
contents.source_url,
contents.created_at,
contents.updated_at,
contents.published_at,
contents.deleted_at,
contents.path,
users.username as owner_username,
content_window.total_rows,
tabcoins_count.total_balance as tabcoins,
tabcoins_count.total_credit as tabcoins_credit,
tabcoins_count.total_debit as tabcoins_debit,
(
SELECT COUNT(*)
FROM contents as children
WHERE children.path @> ARRAY[contents.id]
AND children.status = 'published'
) as children_deep_count
FROM
contents
INNER JOIN
content_window ON contents.id = content_window.id
INNER JOIN
users ON contents.owner_id = users.id
LEFT JOIN LATERAL get_content_balance_credit_debit(contents.id) tabcoins_count ON true; A query de votos (em console.log(
query.text
.replaceAll('$1', `'${fromUserId}'`)
.replaceAll('$2', `'${tabCoinsToDebitFromUser}'`)
.replaceAll('$3', `'${tabCashToCreditToUser}'`)
.replaceAll('$4', `'${contentId}'`)
.replaceAll('$5', `'${tabCoinsToTransactToContent}'`)
.replaceAll('$6', `'${contentOwnerId}'`)
.replaceAll('$7', `'${tabCoinsToTransactToContentOwner}'`)
.replaceAll('$8', `'${originatorType}'`)
.replaceAll('$9', `'${originatorId}'`)
.replaceAll('$10', `'${contentBalanceType}'`),
); Todos esses testes eu realizei no pgAdmin4, mas também notei a diferença ao usar o TabNews pelo localhost. Cheguei a reiniciar o PC, testei direto na sua branch com um banco novo, até avaliei o Explain mas não entendi o que houve. Pode ser algo da minha máquina mesmo, o meu receio era apenas fazer o merge e ficar lento em produção. E se for na minha máquina, não vou conseguir testar o outro PR sem descobrir o problema 😅 Script para popular o bancoMeu script para popular o banco é meio demorado e com algumas gambiarras. Seria bom ter um script melhor para poder deixar no repositório, assim qualquer um pode realizar testes de desempenho. Se você quiser uma base para popular seu banco: async function populateDatabase() {
const batchSize = 100;
const totalToCreate = 30_000;
const totalBatches = Math.ceil(totalToCreate / batchSize);
const allUsers = await user.findAll();
const allContents = await content.findAll(); // Pode passar { per_pages: 10_000 }, por exemplo, e tirar o limite do validator (está em 100)
console.log(`Creating ${totalToCreate} records...`);
let totalSuccessful = 0;
for (let batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
const batchPromises = [];
for (let i = 0; i < batchSize; i++) {
const recordIndex = batchIndex * batchSize + i;
if (recordIndex >= totalToCreate) break;
const randomUserIndex = Math.floor(Math.random() * allUsers.length);
const randomUser = allUsers[randomUserIndex];
let parent_id = null;
if (Math.random() < 0.8 && allContents.length > 0) {
const randomContentIndex = Math.floor(Math.random() * allContents.length);
parent_id = allContents[randomContentIndex].id;
const rate = Math.random() < 0.3 ? -1 : 1;
batchPromises.push(orchestrator.createRate(allContents[randomContentIndex], rate, randomUser.id));
}
// batchPromises.push(createUser());
batchPromises.push(
orchestrator.createContent({
parent_id,
owner_id: randomUser.id,
status: 'published',
title: parent_id ? null : faker.lorem.sentence(),
}),
);
}
const results = await Promise.allSettled(batchPromises);
const successfulCount = results.filter((result) => result.status === 'fulfilled').length;
totalSuccessful += successfulCount;
if (batchIndex % 50 === 0) {
console.log(`More ${(batchIndex + 1) * batchSize} records creation attempts...`);
}
}
console.log(`${totalSuccessful} records created.`);
} Eu coloco essa função no // fake.test.js
import orchestrator from './orchestrator';
describe('performance script', () => {
it('should populate db', async () => {
await orchestrator.populateDatabase();
expect(true).toBe(true);
}, 200_000);
}); A parte de criação de conteúdo demora muito, então costuma dar timeout, mas ele continua rodando o script enquanto não "matar" o Jest. |
Depois de executar No banco que criei nessa branch, ou não teve impacto, ou foi um impacto bem pequeno. |
Legal esse script @Rafatcb! Depois vou popular uma instância usando ele. 👍💪 Qual é o tamanho do volume do contêiner do seu banco? Reparou no tamanho absurdo dos buffers que aparecem nas suas análises? |
Mesmo com o banco populado pelo seu script você deveria conseguir testar com Codespaces ou Gitpod |
Reparei que ficou usou vários GB, achei estranho mas não entendi o motivo. Não senho certeza se para ver o tamanho seria com o comando $ docker system df -v
Images space usage:
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
sj26/mailcatcher latest 7ab5eb1bdf54 6 months ago 95.7MB 0B 95.75MB 1
postgres 14.7-alpine 9d94e6318ef2 10 months ago 242MB 0B 241.7MB 1
Containers space usage:
CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED STATUS NAMES
06aa8b42f6f5 postgres:14.7-alpine "docker-entrypoint.s…" 2 63B 17 hours ago Up About an hour postgres-dev
e3955d7f55b0 sj26/mailcatcher "mailcatcher --foreg…" 0 0B 3 days ago Exited (0) 12 hours ago mailcatcher
Local Volumes space usage:
VOLUME NAME LINKS SIZE
fd184ee451a9328e702a601199288ad0b3f1ffd8bdf4771b88dd1033e2d3b4be 1 952.1MB
infra_postgres_data 1 0B
Build cache usage: 0B
CACHE ID CACHE TYPE SIZE CREATED LAST USED USAGE SHARED
$ docker ps -a --filter volume=fd184ee451a9328e702a601199288ad0b3f1ffd8bdf4771b88dd1033e2d3b4be
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
06aa8b42f6f5 postgres:14.7-alpine "docker-entrypoint.s…" 17 hours ago Up About an hour 0.0.0.0:54320->5432/tcp, :::54320->5432/tcp postgres-dev
Tenho quatro bancos do TabNews:
Tentei testar no Codespaces mas não consegui acessar o banco localmente e nem diretamente (pelo Codespaces) para executar o SQL, então eu apenas acessei uma publicação específica nessa branch e na main, vendo a duração da requisição Quando mudei para a branch |
Não consegui testar mesmo no Codespaces. Criando o banco com menos registros as coisas até funcionam, mas sem conseguir executar apenas a query não dá para ter uma boa noção da duração. Então, fui testar no Windows, usando o DBeaver ao invés do pgAdmin4. Clonei a branch, rodei o script para popular o banco (30 mil usuários, 18,5 mil conteúdos, 76 mil registros em Após usar o Edit: Vou testar no Windows, no |
@Rafatcb, populei um banco com o seu script e acredito que entendi o problema que você dever estar enfrentando. Não tem nenhuma relação com o PR, mas sim com a quantidade de conteúdos publicados em menos de 7 dias pelo script, que é muito maior do que o volume normal do TabNews. A query de ranqueamento não está otimizada para uma quantidade tão grande de conteúdos em 7 dias. Só de rodar essa query uma vez já faz o banco travar em 100% de processamento e nunca mais sair disso. E só de subir o servidor web, essa query já é executada para montar a página inicial. E o banco continua funcionando, mas fica muito lento, já que está ocupado com algo, então isso afeta todas as análises. O desempenho do ranqueamento é a razão de limitarmos aos conteúdos publicados nos últimos 7 dias, pois para montar cada página não basta computar os saldos dos 30 conteúdos da página, mas sim computar os saldos de todos os conteúdos dos últimos 7 dias (mais os com comentários recentes) para descobrir quais serão os 30 conteúdos da página em questão. Só que o script simula uma quantidade muito grande de conteúdos dentro de 7 dias. Pelo mesmo motivo não podermos organizar todos os conteúdos pelos saldos de TabCoins enquanto não tivermos indexado algum cache do saldo já computado. E esse PR não muda nada com relação a isso, já que é esperado que o desempenho da O que esse PR faz de diferente é criar um Apenas para os testes, modifique a query de ranqueamento para lidar com uma quantidade limitada de conteúdos, então tudo deverá funcionar normalmente. É bom verificar também se o seu banco já não está em algum estado de lentidão por algum outro motivo, já que ele está mostrando esses dados de buffer bem estranhos. Adicione limites no começo de WITH
latest_published_child_contents AS (
SELECT
contents.owner_id,
contents.path
FROM contents
WHERE
parent_id IS NOT NULL
AND status = 'published'
AND published_at > NOW() - INTERVAL '1 day'
LIMIT 50
),
latest_interacted_root_contents AS ((
SELECT
contents.id,
contents.owner_id,
contents.published_at,
get_current_balance('content:tabcoin', contents.id) as tabcoins
FROM contents
WHERE
parent_id IS NULL
AND status = 'published'
AND published_at > NOW() - INTERVAL '7 days'
LIMIT 200) |
Sim, provavelmente esse era o problema no Codespaces. O que eu não entendi mesmo foi o problema que você mencionou, do tamanho do Buffer, e por isso resolvi testar no Windows para ver se ocorria alguma mudança (a maior parte do tempo eu programo o TabNews pelo Linux). Limpando o banco (da mesma forma que ocorre nos testes automatizados) e depois populando ele na branch Bom, como você disse que testou e está normal, creio que podemos realizar o merge, mas antes disso, uma dúvida: você não acha que precisa do |
e1ec794
to
a35d4b3
Compare
a35d4b3
to
7ccb5e7
Compare
@Rafatcb, que bom que você falou do índice, pois eu não tinha verificado se ele ainda estava sendo utilizado corretamente. Por ser dentro da função, o uso do índice Alterei o PR e agora estou adicionando um novo índice e removendo o anterior (apenas invertendo a ordem das colunas E pensando que, mesmo que fosse bom usar o Testando os índices eu também peguei um erro na definição da Por fim, se no PR #1607 for adotar a |
Faz sentido 👍
Eu acredito que não seja necessário mudar em todas as situações, porque como a função retorna três valores, o uso dela em uma query acaba não sendo tão simples quanto o de uma função que retorna apenas um valor, então apenas adicionaria mais complexidade onde o somatório de créditos e débitos não é necessário. Faz sentido para você? |
Com certeza! Onde apenas o saldo for necessário, não é preciso usar a Bora pro merge aqui pra poder concluir a #1607? |
7ccb5e7
to
9a082b8
Compare
Em homologação eu já removi todos os deploys de outros PRs para não setar mais o Em produção eu já fiz as trocas dos índices, invertendo as colunas, e já atualizei a Daria para unificar os comandos, mas vou deixar exatamente com foram executados: UPDATE balance_operations AS bo
SET balance_type =
CASE
WHEN e.type != 'update:content:tabcoins' THEN 'content:tabcoin:initial'
WHEN bo.amount > 0 THEN 'content:tabcoin:credit'
WHEN bo.amount < 0 THEN 'content:tabcoin:debit'
ELSE 'content:tabcoin'
END
FROM events AS e
WHERE bo.balance_type = 'content:tabcoin'
AND e.id = bo.originator_id; Cria o tipo UPDATE balance_operations AS bo
SET balance_type =
CASE
WHEN e.type = 'ban:user' THEN 'content:tabcoin:ban'
WHEN e.type = 'system:update:tabcoins' THEN 'content:tabcoin:initial'
WHEN e.type = 'create:content:text_root' THEN 'content:tabcoin:initial'
WHEN e.type = 'create:content:text_child' THEN 'content:tabcoin:initial'
WHEN e.type = 'update:content:text_root' THEN 'content:tabcoin:initial'
WHEN e.type = 'update:content:text_child' THEN 'content:tabcoin:initial'
ELSE 'content:tabcoin'
END
FROM events AS e
WHERE bo.balance_type = 'content:tabcoin:initial'
AND e.id = bo.originator_id; Substitui o UPDATE balance_operations
SET balance_type =
CASE
WHEN amount < 0 THEN 'content:tabcoin:credit'
WHEN amount > 0 THEN 'content:tabcoin:debit'
ELSE 'content:tabcoin'
END
WHERE balance_type = 'content:tabcoin:ban'; Seta os casos de WITH ids_to_update AS (
SELECT bo.id
FROM balance_operations AS bo
INNER JOIN events AS e
ON bo.originator_id = e.id
INNER JOIN contents AS c
ON (e.metadata->>'user_id')::uuid = c.owner_id
AND c.id = recipient_id
WHERE bo.balance_type = 'content:tabcoin:credit'
AND bo.amount < 0
AND e.type = 'ban:user'
)
UPDATE balance_operations AS bo
SET balance_type = 'content:tabcoin:initial'
FROM ids_to_update AS i
WHERE bo.id = i.id; Para verificar se os comandos foram executados com sucesso, basta executar a consulta abaixo, que deve retornar a quantidade zero: SELECT COUNT(*)
FROM balance_operations
WHERE
balance_type = 'content:tabcoin'
OR balance_type = 'content:tabcoin:ban' Por fim é aconselhável fazer um REINDEX INDEX balance_operations_recipient_id_balance_type_index; Apenas para ficar registrado no PR, em caso de reversão das modificações, antes de reverter a migration, seria necessário reverter a coluna UPDATE balance_operations
SET balance_type = 'content:tabcoin'
WHERE
balance_type = 'content:tabcoin:initial'
OR balance_type = 'content:tabcoin:credit'
OR balance_type = 'content:tabcoin:debit'; |
Todos os passos executados em produção com sucesso! 🚀🚀🚀 |
Mudanças realizadas
Alterada a modelagem da tabela
balance_operations
para facilitar a consulta dos saldos de TabCoins dos conteúdos pela funçãoget_content_balance_credit_debit
criada no PR #1607.Foi removido
content:tabcoin
das opções parabalance_operations.balance_type
e substituído porcontent:tabcoin:initial
,content:tabcoin:credit
econtent:tabcoin:debit
.Já foi adicionado no PR atual a versão da função
get_content_balance_credit_debit
que aproveita a mudança embalance_operations
. Agora ela só recebe um parâmetro, que é o ID do conteúdo.As mudanças que envolvem o banco de dados já foram aplicadas em homologação, o que não afeta o funcionando das versões existentes de antes do PR #1607.
Tipo de mudança
Checklist: