1 pontos por GN⁺ 2024-02-11 | 1 comentários | Compartilhar no WhatsApp
  • O PostgreSQL 16 adiciona 10 melhorias ao planejador/otimizador de consultas, ampliando as opções de escolha de planos de execução para consultas com DISTINCT, agregações, joins, funções de janela e tabelas particionadas
  • Ele passa a aproveitar de forma mais agressiva entradas parcialmente ordenadas em SELECT DISTINCT, agregações com ORDER BY/DISTINCT e no processamento após Merge Join, permitindo produzir resultados com menos memória do que uma ordenação completa
  • O suporte a Memoize dentro de UNION ALL, Right Anti Join e Parallel Hash Join para joins FULL/RIGHT foca em reduzir consultas repetidas e o custo de criação de grandes tabelas hash
  • As funções de janela reduzem o processamento desnecessário de RANGE e de WindowAgg que antes precisava ir até o fim, e algumas funções agora podem ser interrompidas antecipadamente conforme a condição
  • Como todas as melhorias vêm ativadas por padrão, vale a pena comparar EXPLAIN e tempos de execução da carga real antes e depois da atualização para o PostgreSQL 16

Escopo das melhorias do planejador no PostgreSQL 16

  • O PostgreSQL 16 introduz várias melhorias no planejador de consultas, permitindo que muitas consultas SQL rodem mais rápido do que em versões anteriores do PostgreSQL
  • O texto detalha as melhorias de planejador incluídas nas notas de lançamento do PG16, junto com comparações de saída de EXPLAIN entre PG15 e PG16 e exemplos de teste reproduzíveis
  • Aqui, o planejador é o componente que em outros bancos de dados relacionais costuma ser chamado de otimizador

Otimizações de ordenação e DISTINCT

  • Uso de Incremental Sort em SELECT DISTINCT

    • O Incremental Sort foi adicionado pela primeira vez no PostgreSQL 13 e reduz custo ao ordenar apenas as colunas restantes quando o resultado já vem ordenado pelas colunas iniciais
    • O planejador do PostgreSQL 16 também passa a considerar Incremental Sort em consultas SELECT DISTINCT
    • Por exemplo, se houver um índice btree na coluna a e a ordem necessária for a, b, é possível obter do índice um resultado já ordenado por a e então ordenar apenas b sempre que o valor de a mudar
    • No quicksort do PostgreSQL, pode ser mais eficiente ordenar vários grupos pequenos do que um único grupo grande
    • Na consulta de exemplo, o PG15 usou HashAggregate e varredura sequencial, enquanto o PG16 escolheu o índice distinct_test_a_idx e Incremental Sort
    • Em PG16, Presorted Key: a significa que a entrada já ordenada por a foi aproveitada
    • O método com hash do PG15 despejou cerca de 30MB em disco, enquanto o pico de memória do Incremental Sort no PG16 foi de 26KB
    • O tempo de execução caiu de 414.226ms no PG15 para 263.167ms no PG16
  • Otimização de agregações com ORDER BY ou DISTINCT

    • Até o PostgreSQL 15, funções de agregação com cláusulas ORDER BY ou DISTINCT sempre faziam a ordenação dentro do nó Aggregate
    • O planejador do PostgreSQL 16 pode montar um plano de execução que forneça linhas na ordem correta ao nó Aggregate, e o executor ignora a ordenação interna se a entrada já estiver ordenada
    • No exemplo com COUNT(DISTINCT b), tanto PG15 quanto PG16 usam GroupAggregate e Index Only Scan, mas a saída do PG15 mostra temp read=4540 written=4560
    • Esse I/O de arquivo temporário é resultado da ordenação implícita do PG15 ter sido despejada em disco
    • Na saída do PG16, esse I/O temporário não aparece, e o tempo de execução melhora de 302.693ms no PG15 para 115.534ms no PG16, mais de 2x mais rápido

Melhorias em consultas repetidas e planos de join

  • Aplicação de Memoize dentro de UNION ALL

    • O nó de plano Memoize foi introduzido no PostgreSQL 14 e funciona como uma camada de cache entre um Nested Loop parametrizado e sua entrada interna
    • O planejador do PostgreSQL 16 passa a considerar Memoize mesmo quando há uma consulta UNION ALL na parte interna de um Nested Loop parametrizado
    • No exemplo, o PG15 executou Append 1 milhão de vezes, enquanto o PG16 colocou Memoize acima de Append
    • O Memoize do PG16 registrou Hits: 999990, Misses: 10, Memory Usage: 2kB
    • O número de execuções de Append caiu de 1 milhão no PG15 para 10 no PG16
    • O tempo de execução passou de 1926.151ms no PG15 para 282.120ms no PG16, cerca de 6x mais rápido
  • Suporte a Right Anti Join

    • Em Hash Join com INNER JOIN, normalmente é vantajoso construir a tabela hash sobre a tabela menor
    • Uma tabela hash menor exige menos trabalho para ser criada, é mais amigável ao cache da CPU e reduz a chance de stalls enquanto a CPU espera dados da memória principal
    • Antes do PostgreSQL 16, Anti Join colocava sempre na parte interna do join a tabela mencionada em NOT EXISTS, o que podia forçar a criação da tabela hash sobre a tabela maior
    • O PostgreSQL 16 adiciona suporte a Right Anti Join, permitindo aplicar hash no menor dos dois lados
    • No exemplo, o PG15 aplicou hash na tabela large com 1 milhão de linhas e usou 6446KB de memória, enquanto o PG16 aplicou hash na tabela small com 100 linhas e usou apenas 12KB
    • O tempo de execução caiu de 139.023ms no PG15 para 77.076ms no PG16, quase pela metade
  • Parallel Hash Join para joins FULL/RIGHT

    • O PostgreSQL 11 introduziu Parallel Hash Join, no qual vários workers paralelos participam da criação de uma única tabela hash
    • No PostgreSQL 16, Parallel Hash Join passa a oferecer suporte aos tipos de join FULL e RIGHT
    • Isso permite executar em paralelo também planos de FULL OUTER JOIN e Right Join
    • No exemplo de FULL JOIN, o PG15 usou um único Hash Full Join, enquanto o PG16 usou Parallel Hash Full Join e Gather
    • Na saída do PG16 aparecem Workers Planned: 1 e Workers Launched: 1
    • O tempo de execução caiu bastante, de 220.677ms no PG15 para 129.769ms no PG16

Otimizações de funções de janela

  • Eliminação de processamento desnecessário de RANGE

    • Em funções de janela como row_number(), rank(), dense_rank(), percent_rank(), cume_dist() e ntile(), se a cláusula de janela não especifica ROWS, o PostgreSQL usa a opção padrão RANGE
    • A opção RANGE precisa olhar linhas anteriores para encontrar peer rows com o mesmo valor de ordenação, e isso pode ficar caro quando há muitos valores iguais no ORDER BY
    • Para essas funções, o comportamento não muda entre ROWS e RANGE, mas antes do PostgreSQL 16 o executor não conseguia distinguir isso e precisava verificar peer rows em todos os casos
    • O planejador do PostgreSQL 16 sabe quais funções de janela são afetadas por ROWS/RANGE e repassa essa informação ao executor para que ele pule o processamento desnecessário
    • No exemplo row_number() <= 10, o PG15 leu 50.410 linhas do índice antes de parar, enquanto o PG16 leu apenas 11 linhas
    • O PG16 aproveita o fato de que, ao chegar em row_number 11, não pode mais haver linhas que satisfaçam a condição <= 10
    • O tempo de execução caiu de 29.775ms no PG15 para 0.058ms no PG16, mais de 500x mais rápido
  • Ampliação da interrupção antecipada para funções de janela monotônicas

    • O PostgreSQL 15 passou a permitir encerrar cedo a execução de WindowAgg quando uma condição na cláusula WHERE se torna falsa para determinada função de janela e não pode voltar a ser verdadeira
    • O PostgreSQL 16 amplia essa otimização também para ntile(), cume_dist() e percent_rank()
    • No PostgreSQL 15, isso se aplicava apenas a row_number(), rank(), dense_rank(), count() e count(*)
    • No exemplo percent_rank() <= 0.01, o PG15 tratou a condição como Filter na subconsulta, e o WindowAgg processou todas as 50.000 linhas
    • O PG16 usa a mesma condição como Run Condition, interrompendo a execução de WindowAgg antecipadamente
    • O tempo de execução caiu de 84.358ms no PG15 para 19.454ms no PG16, mais de 4x mais rápido

Tabelas particionadas e tratamento de DISTINCT trivial

  • Remoção de LEFT JOIN em tabelas particionadas

    • O PostgreSQL já consegue há muito tempo remover LEFT JOIN quando ele não é necessário para a consulta e não pode causar duplicação de linhas
    • Antes do PostgreSQL 16, a remoção de LEFT JOIN não era suportada para tabelas particionadas
    • Isso acontecia porque faltava, para tabelas particionadas, a prova necessária de que as linhas internas não poderiam duplicar as externas
    • O planejador do PostgreSQL 16 passa a aplicar a otimização de remoção de LEFT JOIN também em tabelas particionadas
    • Essa otimização pode ser especialmente útil em views
      • porque uma view pode ter muitas colunas, mas a consulta real nem sempre precisa ler todas elas
    • No exemplo, o plano do PG15 inclui o join com part_tab, enquanto o plano do PG16 faz apenas uma varredura sequencial em normal_table
  • DISTINCT com resultado garantidamente único tratado como Limit

    • O planejador do PostgreSQL pode omitir o nó de plano de remoção de duplicatas se conseguir detectar que todas as linhas têm o mesmo valor
    • O PostgreSQL 16 aproveita o fato de que, quando todas as colunas alvo de DISTINCT estão fixadas por condições de igualdade na cláusula WHERE, o resultado só pode conter aquele mesmo valor e, portanto, pode ser tratado com LIMIT 1
    • Na consulta de exemplo SELECT DISTINCT a,b,c FROM abc WHERE a = 5 AND b = 5 AND c = 5, cada coluna de DISTINCT está restrita ao mesmo valor
    • O PG15 lê o resultado inteiro e o reduz a 1 linha com o operador Unique
    • O PG16 usa Limit e varredura sequencial para retornar apenas 1 linha
    • O tempo de execução caiu de 30.381ms no PG15 para 0.025ms no PG16, mais de 1200x mais rápido

Uso ampliado de Incremental Sort após Merge Join

  • Antes do PostgreSQL 16, ao considerar Merge Join, o planejador só usava a ordem do join quando ela correspondia exatamente às exigências das operações superiores de DISTINCT, GROUP BY ou ORDER BY
  • Essa regra não refletia bem o fato de que Incremental Sort pode aproveitar entradas parcialmente ordenadas nas operações superiores
  • O PostgreSQL 16 flexibiliza essa regra de consideração da ordem de Merge Join: em vez de exigir correspondência exata, basta que pelo menos uma coluna inicial esteja ordenada corretamente
  • Com isso, o planejador pode usar Incremental Sort com mais frequência para adaptar o resultado de Merge Join às necessidades da operação superior
    • Como o Incremental Sort trabalha com entradas parcialmente ordenadas e ordena em pequenos lotes, ele pode reduzir o uso de memória e o número de comparações em relação a uma ordenação completa
  • No exemplo, o PG15 usou uma ordenação completa Sort após Merge Join, enquanto o PG16 usou Incremental Sort
    • O pico de memória do Incremental Sort no PG16 foi de 26KB
    • O tempo de execução caiu levemente de 1010.738ms no PG15 para 915.589ms no PG16, mas o uso de memória na ordenação diminuiu bastante

Como isso se aplica na prática

  • As 10 melhorias do planejador no PostgreSQL 16 vêm todas ativadas por padrão
  • Cada otimização é aplicada em todos os casos possíveis ou escolhida seletivamente quando o planejador entende que ela será útil
  • Se você usa uma versão anterior do PostgreSQL, vale executar sua carga real no PostgreSQL 16 para verificar quais consultas ficam mais rápidas
  • Feedback de uso real pode ser compartilhado na mailing list pgsql-general@postgresql.org

1 comentários

 
GN⁺ 2024-02-11
Comentários do Hacker News
  • Seria muito bom se o planejador de consultas do PostgreSQL pudesse replanejar a consulta no meio da execução
    Consultas patologicamente lentas muitas vezes acontecem porque o planejador não conhece as informações necessárias sobre a distribuição dos dados e estima mal o custo, o que facilmente gera uma diferença de 1000x, como uma execução levar 1 ms em vez de 1 segundo
    Como as estatísticas da tabela nunca podem ser 100% precisas, seria bom que, se após iniciar a consulta o progresso estivesse mais lento do que o esperado, o planejador pudesse receber de novo informações do andamento atual, como número de páginas varridas e tuplas correspondidas, para criar um novo plano
    Mas o PostgreSQL envia os resultados em streaming, em vez de produzir tudo e só então enviar, então mudar o plano no meio exigiria rastrear os resultados já enviados ao cliente, o que implica uma grande mudança de infraestrutura
    Além disso, o cliente pode até inverter a direção no meio da consulta e pedir novamente os resultados anteriores em ordem inversa, o que aumenta ainda mais a complexidade

    • Como autor do blog e committer do PostgreSQL, também acho que seria bom ter esse recurso. Mas o problema de enviar tuplas ao cliente é ainda mais complicado do que foi dito acima
      Isso porque nem sequer há garantia de que o novo plano retornará as mesmas tuplas. Por exemplo, em SELECT * FROM table LIMIT 10, sem ORDER BY, não é determinístico quais tuplas sairão
      Talvez fosse mais fácil empilhar X tuplas em uma fila e só começar a enviá-las quando a fila encher. Depois que a fila estiver cheia, consideraríamos que já é tarde demais para replanejar e o plano atual ficaria fixo
      O usuário poderia ajustar X para ganhar mais tempo para mudar o plano, em troca de usar mais memória e aumentar a latência até a primeira tupla
    • Outra perspectiva seria permitir consultas com planejamento demorado. Poderia ser permitido gastar 1 segundo ou alguns segundos escolhendo o plano ideal e, durante esse processo, coletar mais estatísticas ou até executar a consulta por um instante
    • Fico curioso sobre em que casos é útil a funcionalidade de o cliente inverter a direção no meio da consulta e receber de novo os resultados anteriores em ordem inversa
    • Tenho curiosidade se, quando a consulta não determina completamente a ordem de classificação, o plano de consulta pode afetar a ordem dos resultados. Se sim, a abordagem proposta pode ser quase impossível
      A nova consulta não poderia simplesmente pular os N primeiros resultados; ela teria de conferir cada linha já enviada contra um dicionário
    • Este artigo e os trabalhos citados nele podem interessar: https://arxiv.org/pdf/1902.08291
  • Uso esta ferramenta para visualizar consultas: https://explain.dalibo.com/
    Também existe https://www.pgexplain.dev/; antes a saída parecia pior, mas agora os dois parecem semelhantes

    • A ferramenta é excelente e eu a uso, mas ainda não entendo o suficiente em profundidade para olhar para as partes do plano que parecem ruins e saber como corrigir minha abordagem
    • Pelo perfil, você é CTO de fintech; fico curioso sobre como lida com o aviso da ferramenta de que “é recomendado não enviar informações importantes ou sensíveis”
      Queria saber se existe alguma ferramenta de sanitização de planos de execução que ajude nessa situação
  • Melhorias no planejador de consultas são sempre bem-vindas, e essa é uma parte muito importante do banco de dados. Claro que normalmente isso fica mais visível quando não funciona do jeito que eu quero
    Uma parte que pessoalmente me frustrou bastante é o JIT das versões recentes do PostgreSQL. As heurísticas para decidir quando usá-lo não parecem nada robustas
    Vi isso em consultas típicas geradas por ORM: a consulta em si é simples, mas acaba puxando muitas tabelas por causa dos joins. Sem JIT, termina em poucos milissegundos, mas o JIT gasta mais 1 a 1,5 segundo e fica absurdamente lento até com pouco volume de dados
    Agora já sei que basta desativar o JIT, mas para usuários que ainda não entendem por que está lento isso pode prejudicar bastante a impressão sobre o PostgreSQL. Gosto do PostgreSQL, mas deixar o JIT ativado por padrão parece arriscado demais

    • Como autor do blog e committer do PostgreSQL, concordo fortemente que o código que decide usar JIT ou não precisa melhorar
      No PG16, ele olha apenas para o custo total estimado do plano e não considera quantas expressões precisam ser compiladas
      Compilar algumas expressões é rápido, mas se você consulta uma tabela particionada com centenas de partições e todas elas entram no plano, o compilador JIT passa a ter muito trabalho
      Tenho um código com um colega para melhorar isso, mas neste momento não é certo que ele entre no PG17
    • Outra coisa que parece estranha no JIT é que o código gerado não é armazenado em cache. Muitas vezes essa é a parte mais cara da execução da consulta, então não entendo por que não fazem cache disso
      Mesmo procurando discussões sobre JIT na mailing list do PostgreSQL, não encontrei uma razão convincente
      Em cargas de trabalho OLTP, faz sentido desativar o JIT
    • Considero o JIT quase um fracasso. A intenção era boa, mas o LLVM não é a ferramenta certa para isso. Deixei desativado globalmente
      Não uso ORM, então não é simplesmente um problema de padrões de consulta estranhos
      Em compensação, a paralelização de consultas pode ser realmente útil e, acima de tudo, raramente causa dano
    • Recentemente encontrei um bug esquisito relacionado a JIT em produção
      Atualizei alguns pacotes com apt e, de repente, uma consulta grande executada a cada 5 minutos começou a falhar. Mais especificamente, o PostgreSQL simplesmente encerrava a conexão silenciosamente no meio da execução, sem nem registrar logs
      Testando manualmente com EXPLAIN, confirmei que só quebrava a variante da consulta que passava a usar JIT; a que não usava continuava funcionando. Ao desativar o JIT, tudo voltou ao normal
    • Fico curioso se já tentaram usar prepared statements para compilar uma única vez e reutilizar o resultado da compilação em cada execução dessa consulta
  • Fico curioso sobre com frequência essas mudanças realmente ajudam em consultas reais. Em particular, a mudança de “usar Limit em vez de Unique para implementar DISTINCT quando possível” parece algo que só se aplicaria a consultas muito tolas
    Fico me perguntando se os desenvolvedores do PostgreSQL têm alguma fonte de informação para avaliar isso

    • Parece que ajudará com bastante frequência. DISTINCT é algo que desenvolvedores menos experientes frequentemente colocam para tentar consertar uma consulta ruim, e normalmente uma das primeiras coisas que se faz ao começar a melhorar performance é reescrever a consulta para que isso deixe de ser necessário
      Se a melhoria de DISTINCT tornar o sistema mais robusto contra consultas ruins, já há muito a ganhar. Não vai corrigir todos os problemas, mas qualquer melhoria é bem-vinda
    • Como autor do blog e também dessa funcionalidade, isso de fato surgiu na lista de e-mails pgsql-hackers
      Concordo que a chance de se aplicar com frequência é baixa, mas o lado bom é que detectar se ela se aplica era tão simples quanto verificar se um ponteiro é NULL
      A detecção é muito simples e, na maioria dos casos, não se aplicará, mas quando for aplicável pode trazer um ganho de performance considerável
    • O problema é que ORMs têm o hábito de gerar consultas muito tolas, e os desenvolvedores se recusam a corrigi-las escrevendo SQL à mão porque, por algum motivo, isso não seria puro
      Talvez não seja um problema muito comum, mas eu não me surpreenderia se aparecesse de vez em quando
    • No meu emprego anterior, por razões legadas, permitíamos endereços de e-mail duplicados na tabela de usuários, mas não queríamos inserir novos duplicados, então antes de criar um novo usuário executávamos a consulta select distinct email from users where email = ?
      Acho que nunca havia mais de 100 linhas com o mesmo e-mail. A maioria era de usuários de teste que poderiam ter sido apagados, mas enfim, me desviei do assunto
  • Seria bom se o PostgreSQL tivesse um modo estrito para testes de aplicações. Um modo que, olhando apenas para a própria consulta, independentemente de estatísticas, retornasse erro se existir um índice que melhoraria a consulta assintoticamente e esse índice estiver ausente
    Também seria bom ter um comando CREATE INDICES FOR para criar esse índice em upgrades da aplicação, e um modo de criação automática de índices para uso interativo e de desenvolvimento
    No geral, o sistema deveria ser projetado para que execuções assintoticamente subótimas jamais aconteçam

  • Não entendo por que não implementam hints

    • Existe a extensão pg_hint_plan. O perigo dos hints é que, mesmo estando corretos quando foram escritos, eles podem piorar as coisas quando o tamanho da tabela ou a distribuição dos dados muda
      Pelo que lembro de discussões antigas sobre hints, não havia oposição geral se fosse uma forma que não amarrasse demais o planner e ainda permitisse adaptação a mudanças nos dados subjacentes
      Por exemplo, em vez de especificar que um determinado predicado combina com 10 linhas, informar que há correlação entre duas colunas
    • Discussão relacionada: Why PostgreSQL doesn't have query hints
      https://news.ycombinator.com/item?id=2179433 (60 comentários, 2011)
      A posição oficial no wiki do PostgreSQL está em https://wiki.postgresql.org/wiki/OptimizerHintsDiscussion
      A posição é: “não há interesse em hints exatamente da forma como costumam ser implementados em outros bancos de dados”
      Entre os problemas dos sistemas de hints existentes estão piora na manutenção do código da aplicação, dificuldade para upgrades, incentivo a maus hábitos de DBAs e falta de adequação ao crescimento do volume de dados
      Não quero culpar essa posição, mas é frustrante quando o PostgreSQL escolhe um plano ruim e você não consegue convencê-lo a fazer a escolha razoável
  • Um amigo meu, DBA da Microsoft voltado para empresas de médio porte, disse que não dá para fazer trabalho sério com PostgreSQL. Disse até que ficou chocado ao descobrir que o PostgreSQL nem tinha um planejador de consultas
    Deixando a zombaria de lado por um momento, fico me perguntando se há alguma plausibilidade na afirmação mais ampla de que o MSSQL consegue lidar com uma escala para a qual o PostgreSQL seria inadequado. Minha intuição diz que isso é absurdo, mas não sou DBA nem de longe

    • Há um certo ponto nisso. Se você quer um banco de dados que faça quase qualquer coisa de que precise bem o suficiente, MSSQL e Oracle provavelmente dão conta
      Eles historicamente resolveram problemas jogando dinheiro e hardware, ou seja, mais dinheiro, até a situação se resolver. Claro que há muita tecnologia inteligente ali, mas no fundo houve muito mais engenharia investida por muito mais tempo
      Eles conseguem escalar horizontalmente para além do que o PostgreSQL consegue fazer de forma razoável
      Dito isso, o PostgreSQL está alcançando esse nível, e pode-se argumentar que MySQL/MariaDB sempre tiveram uma boa história nessa área. As opções de escala horizontal continuam melhorando
      Hoje já ficou mais fácil operar clusters PostgreSQL de vários terabytes com poucas máquinas e lidar com tráfego alto, deixando o “big data” em bancos mais especializados. O jeito antigo de enfiar tudo em MSSQL/Oracle talvez já esteja um pouco ultrapassado
    • Já desenvolvi bastante com MSSQL, e o PostgreSQL tem algumas ausências de funcionalidade que podem surpreender um pouco
      O que seu amigo pode ter querido dizer é que o PostgreSQL não tem uma forma de cachear ou fixar planos de consulta. O PostgreSQL replana cada instrução, a menos que você use instruções preparadas manualmente, e mesmo assim isso só funciona por conexão
      O MSSQL faz cache e reutiliza planos há muito tempo, então o planejador pode gastar mais tempo elaborando o plano. Ele também tem hints e permite fixar planos
      O PostgreSQL realmente precisa de hints. Mesmo com um ótimo otimizador, às vezes eu sei mais e quero conseguir fazê-lo me ouvir
      Além disso, o PostgreSQL não tem um verdadeiro índice clusterizado, e toda tabela é heap. No MSSQL isso é usado com bastante frequência; normalmente você define a chave primária como índice clusterizado, então a própria tabela vira o índice e não há indireção ao buscar pela chave
      Curiosamente, no SQLite é o contrário: a tabela sempre tem um índice clusterizado, você o crie ou não, e o MSSQL deixa você escolher entre heap e tabela organizada por índice
    • O PostgreSQL tem um planejador de consultas. O texto inteiro é sobre melhorias nele. Então ou houve um problema de comunicação, ou seu amigo não conhece PostgreSQL de jeito nenhum
      Há exemplos de bancos PostgreSQL muito grandes funcionando bem, então o PostgreSQL certamente consegue escalar
      Dito isso, o SQL Server tem recursos que o PostgreSQL não tem, e se eles forem importantes, pode ser uma opção melhor para certos casos de uso. No fim, são bancos diferentes com pontos fortes e fracos diferentes
    • Já usei os dois tanto em OLTP quanto em data warehousing, e ambos são bons
      A princípio eu ia escrever que teria recomendado migrar a empresa para PostgreSQL se não fosse por um aplicativo de fornecedor que exigia SQL Server
      Mas então percebi o quanto daria trabalho substituir coisas que a Microsoft já inclui, como reporting services, integration services, jobs, integração com AD e service broker. notify/listen não tem tipos de mensagem
      Já não uso mais analysis services, mas quando usava isso também teria sido difícil de substituir
      Esse tipo de coisa prende as pessoas. Nem faço ideia de quanto tempo levaria para substituir tudo isso, e gastar um ano trocando algo que você já tem não costuma dar um bom retorno sobre o investimento
    • O Aurora da AWS parece lidar com isso muito bem e pretende ser um substituto drop-in para PostgreSQL e MySQL
  • Fico me perguntando por que isso foi publicado no citusdata em vez de no postgresql.org. Não sei se é algo só para funcionalidades pagas ou algum acréscimo open source

    • Porque o autor trabalha na Citus Data, e inclusive escreveu pessoalmente algumas dessas otimizações
  • Quando será que vamos poder usar índices para acelerar consultas com IS NOT DISTINCT FROM ;)