Balanceamento de gravação e leitura de banco de dados

imagem

Em um artigo anterior , descrevi o conceito e a implementação de um banco de dados construído com base em funções, não em tabelas e campos, como nos bancos de dados relacionais. Deu muitos exemplos mostrando as vantagens dessa abordagem em relação ao clássico. Muitos os acharam não suficientemente convincentes.

Neste artigo, mostrarei como esse conceito permite equilibrar rápida e convenientemente a escrita e a leitura no banco de dados sem nenhuma alteração na lógica do trabalho. Eles tentaram implementar funcionalidades semelhantes no DBMS comercial moderno (em particular, Oracle e Microsoft SQL Server). No final do artigo, mostrarei o que aconteceu com eles, para dizer o mínimo, não muito.

Descrição do produto


Como antes, para uma melhor compreensão, começarei a descrição com exemplos. Suponha que precisamos implementar uma lógica que retorne uma lista de departamentos com o número de funcionários e o salário total.

Em um banco de dados funcional, ele terá a seguinte aparência:
CLASS Department '';
name '' = DATA STRING [ 100 ] (Department);

CLASS Employee '';
department '' = DATA Department (Employee);
salary '' = DATA NUMERIC [ 10 , 2 ] (Employee);

countEmployees '- ' (Department d) =
GROUP SUM 1 IF department(Employee e) = d;
salarySum ' ' (Department d) =
GROUP SUM salary(Employee e) IF department(e) = d;

SELECT name(Department d), countEmployees(d), salarySum(d);
A complexidade de executar essa consulta em qualquer DBMS será equivalente a O (número de funcionários) , pois para esse cálculo você precisa varrer a tabela inteira de funcionários e agrupá-los por departamento. Também haverá algumas pequenas adições (acreditamos que há muito mais funcionários que departamentos), dependendo do plano escolhido O (número de log de funcionários) ou O (número de departamentos) para agrupamento e assim por diante.

É claro que a sobrecarga para execução pode ser diferente em diferentes DBMSs, mas a complexidade não muda de forma alguma.

Na implementação proposta, o DBMS funcional formará uma subconsulta, que calculará os valores necessários para o departamento e, em seguida, fará um JOIN com a tabela de departamento para obter o nome. No entanto, para cada função, ao declarar, é possível especificar um marcador MATERIALIZED especial. O sistema criará automaticamente um campo apropriado para cada uma dessas funções. Quando um valor da função muda, o valor do campo muda na mesma transação. Ao acessar esta função, uma apelação já será feita no campo calculado.

Em particular, se você colocar MATERIALIZED para as funções countEmployees e employeeSum , na tabela com a lista de departamentos serão adicionados dois campos nos quais o número de funcionários e o salário total serão armazenados. Com qualquer alteração nos funcionários, seus salários ou afiliação aos departamentos, o sistema alterará automaticamente os valores desses campos. A consulta acima começará a acessar esses campos diretamente e será executada para O (número de departamentos) .

Quais são as limitações? Apenas uma coisa: essa função deve ter um número finito de valores de entrada para os quais seu valor está definido. Caso contrário, será impossível construir uma tabela que armazene todos os seus valores, pois não pode haver uma tabela com um número infinito de linhas.

Um exemplo:
employeesCount ' > N' (Department d, NUMERIC [ 10 , 2 ] N) =
GROUP SUM salary(Employee e) IF department(e) = d AND salary(e) > N;
Esta função é definida para um número infinito de valores do número N (por exemplo, qualquer valor negativo é adequado). Portanto, não pode ser colocado MATERIALIZADO. Portanto, essa é uma limitação lógica e não técnica (ou seja, não porque não fomos capazes de implementar isso). Caso contrário, não há restrições. Você pode usar agrupamento, classificação, AND e OR, PARTITION, recursão, etc.

Por exemplo, na tarefa 2.2 do artigo anterior, você pode colocar MATERIALIZED nas duas funções:
bought '' (Customer c, Product p, INTEGER y) =
GROUP SUM sum(Detail d) IF
customer(order(d)) = c AND
product(d) = p AND
extractYear(date(order(d))) = y MATERIALIZED ;
rating '' (Customer c, Product p, INTEGER y) =
PARTITION SUM 1 ORDER DESC bought(c, p, y), p BY c, y MATERIALIZED ;
SELECT contactName(Customer c), name(Product p) WHERE rating(c, p, 1997 ) < 3 ;
O próprio sistema criará uma tabela com chaves dos tipos Customer , Product e INTEGER , adicionará dois campos a ela e atualizará os valores de campo nelas com quaisquer alterações. Após chamadas adicionais para essas funções, elas não serão calculadas, mas os valores dos campos correspondentes serão lidos.

Usando esse mecanismo, você pode, por exemplo, livrar-se da recursão (CTE) nas consultas. Em particular, considere os grupos que compõem a árvore usando o relacionamento filho / pai (cada grupo tem um link para seu pai):
parent = DATA Group (Group);
Em um banco de dados funcional, a lógica de recursão pode ser definida da seguinte maneira:
level (Group child, Group parent) = RECURSION 1l IF child IS Group AND parent == child
STEP 2l IF parent == parent($parent);
isParent (Group child, Group parent) = TRUE IF level(child, parent) MATERIALIZED ;
Como MATERIALIZED é afixado para a função isParent , será criada uma tabela com duas chaves (grupos), na qual o campo isParent será verdadeiro somente se a primeira chave for um descendente da segunda. O número de entradas nesta tabela será igual ao número de grupos vezes a profundidade média da árvore. Se for necessário, por exemplo, calcular o número de descendentes de um determinado grupo, você poderá acessar esta função:
childrenCount (Group g) = GROUP SUM 1 IF isParent(Group child, g);
Não haverá CTE na consulta SQL. Em vez disso, haverá um simples GROUP BY.

Usando esse mecanismo, você também pode desnormalizar facilmente o banco de dados, se necessário:
CLASS Order '' ;
date '' = DATA DATE (Order);

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail);
date '' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED ;
Quando você chama a função de data para a linha do pedido, a leitura será da tabela com as linhas do pedido do campo para o qual existe um índice. Ao alterar a data do pedido, o próprio sistema recalcula automaticamente a data não normalizada na linha.

Os benefícios


Por que todo esse mecanismo é necessário? Nos DBMSs clássicos, sem reescrever consultas, um desenvolvedor ou DBA só pode alterar índices, determinar estatísticas e informar ao planejador de consultas como executá-las (além disso, as HINTs estão disponíveis apenas em DBMSs comerciais). Por mais que tentem, eles não poderão atender à primeira solicitação do artigo para O (número de departamentos) sem alterar as solicitações e adicionar gatilhos. No esquema proposto, no estágio de desenvolvimento, você não precisa pensar na estrutura do armazenamento de dados e em quais agregações usar. Tudo isso pode ser facilmente alterado em tempo real, diretamente em operação.

Na prática, é o seguinte. Algumas pessoas desenvolvem lógica diretamente com base na tarefa. Eles não são versados ​​em algoritmos e sua complexidade, nem em planos de execução, nem em tipos de join'ov, nem em nenhum outro componente técnico. Essas pessoas são mais analistas de negócios do que desenvolvedores. Então, tudo entra em teste ou operação. O log de consultas longas está ativado. Quando uma solicitação longa é detectada, outras pessoas (mais técnicas - na verdade, DBA) decidem incluir MATERIALIZED em alguma função intermediária. Assim, a gravação fica um pouco mais lenta (já que é necessário atualizar um campo adicional em uma transação). No entanto, não apenas essa solicitação é significativamente acelerada, mas também todas as outras que usam essa função. Ao mesmo tempo, tomar uma decisão sobre qual função específica se materializar é relativamente simples. Dois parâmetros principais: o número de possíveis valores de entrada (exatamente quantos registros haverá na tabela correspondente) e com que frequência é usado em outras funções.

Análogos


Os DBMSs comerciais modernos têm mecanismos semelhantes: VIEW MATERIALIZED com FAST REFRESH (Oracle) e INDEXED VIEW (Microsoft SQL Server). No PostgreSQL, o MATERIALIZED VIEW não pode ser atualizado em uma transação, mas apenas mediante solicitação (e mesmo com restrições muito rígidas), portanto, não consideramos isso. Mas eles têm vários problemas, o que limita bastante o seu uso.

Primeiro, você pode ativar a materialização apenas se você já criou uma VIEW regular. Caso contrário, você terá que reescrever as solicitações restantes para acessar a exibição recém-criada para usar essa materialização. Ou deixe como está, mas será pelo menos ineficaz se já houver determinados dados calculados, mas muitas consultas nem sempre os usam, mas calculam novamente.

Em segundo lugar, eles têm um grande número de restrições:

Oracle
5.3.8.4 Restrições gerais na atualização rápida

A consulta de definição da visão materializada é restrita da seguinte maneira:
  • A visualização materializada não deve conter referências a expressões não repetidas como SYSDATE e ROWNUM .
  • A exibição materializada não deve conter referências aos tipos de dados RAW ou LONG RAW .
  • Ele não pode conter uma subconsulta da lista SELECT .
  • Ele não pode conter funções analíticas (por exemplo, RANK ) na cláusula SELECT .
  • Ele não pode fazer referência a uma tabela na qual um índice XMLIndex está definido.
  • Não pode conter uma cláusula MODEL .
  • Ele não pode conter uma cláusula HAVING com uma subconsulta.
  • Ele não pode conter consultas aninhadas que possuem ANY , ALL ou NOT EXISTS .
  • Não pode conter uma cláusula [START WITH …] CONNECT BY .
  • Ele não pode conter várias tabelas de detalhes em sites diferentes.
  • ON vistas materializadas ON COMMIT não podem ter tabelas de detalhes remotas.
  • As visualizações materializadas aninhadas devem ter uma junção ou agregação.
  • As visualizações de junção materializada e as visualizações agregadas materializadas com uma cláusula GROUP BY não podem ser selecionadas em uma tabela organizada por índice.

5.3.8.5 Restrições à atualização rápida em vistas materializadas apenas com junções

A definição de consultas para visualizações materializadas apenas com junções e nenhum agregado possui as seguintes restrições na atualização rápida:
  • Todas as restrições de " Restrições gerais à atualização rápida ".
  • Eles não podem ter cláusulas ou agregados GROUP BY .
  • Rowids de todas as tabelas na lista FROM devem aparecer na lista SELECT da consulta.
  • Os logs de exibição materializada devem existir com linhas para todas as tabelas base na lista FROM da consulta.
  • Você não pode criar uma exibição materializada atualizável rápida de várias tabelas com junções simples que incluem uma coluna de tipo de objeto na SELECT .

Além disso, o método de atualização que você escolher não será idealmente eficiente se:
  • A consulta de definição usa uma junção externa que se comporta como uma junção interna. Se a consulta de definição contiver essa associação, considere reescrever a consulta de definição para conter uma associação interna.
  • A lista SELECT da visualização materializada contém expressões em colunas de várias tabelas.

5.3.8.6 Restrições à atualização rápida em vistas materializadas com agregados

A definição de consultas para visualizações materializadas com agregações ou junções possui as seguintes restrições na atualização rápida:

A atualização rápida é suportada para as visualizações materializadas ON COMMIT e ON DEMAND , no entanto, as seguintes restrições se aplicam:
  • Todas as tabelas na visão materializada devem ter logs de visão materializada e os logs de visão materializada devem:
    • Contenha todas as colunas da tabela referenciada na visualização materializada.
    • Especifique com ROWID e INCLUDING NEW VALUES .
    • Especifique a cláusula SEQUENCE se a tabela tiver uma combinação de inserções / cargas diretas, exclusões e atualizações.

  • Apenas SUM , COUNT , AVG , VARIANCE , VARIANCE , MIN e MAX são suportados para atualização rápida.
  • COUNT(*) deve ser especificado.
  • As funções agregadas devem ocorrer apenas como a parte mais externa da expressão. Ou seja, agregados como AVG(AVG(x)) ou AVG(x) + AVG(x) não são permitidos.
  • Para cada agregado, como AVG(expr) , a COUNT(expr) correspondente COUNT(expr) deve estar presente. A Oracle recomenda que SUM(expr) seja especificado.
  • Se VARIANCE(expr) ou STDDEV(expr ) for especificado, COUNT(expr) e SUM(expr) deverão ser especificados. A Oracle recomenda que SUM(expr *expr) seja especificado.
  • A coluna SELECT na consulta de definição não pode ser uma expressão complexa com colunas de várias tabelas base. Uma solução possível para isso é usar uma exibição materializada aninhada.
  • A lista SELECT deve conter todas as colunas GROUP BY .
  • A visualização materializada não se baseia em uma ou mais tabelas remotas.
  • Se você usar um tipo de dados CHAR nas colunas de filtro de um log de exibição materializada, os conjuntos de caracteres do site mestre e a exibição materializada deverão ser os mesmos.
  • Se a visualização materializada tiver um dos seguintes, a atualização rápida será suportada apenas em inserções DML convencionais e cargas diretas.
    • Vistas materializadas com agregados MIN ou MAX
    • Visualizações materializadas que possuem SUM(expr) mas não COUNT(expr)
    • Visualizações materializadas sem COUNT(*)

    Essa visão materializada é denominada visão materializada somente para inserção.
  • Uma visualização materializada com MAX ou MIN é rapidamente atualizável após excluir ou misturar instruções DML, se não tiver uma cláusula WHERE .
    A atualização rápida máxima / min após a exclusão ou a DML mista não tem o mesmo comportamento que o caso somente de inserção. Exclui e recalcula os valores máx / min para os grupos afetados. Você precisa estar ciente de seu impacto no desempenho.
  • As visualizações materializadas com visualizações nomeadas ou subconsultas na cláusula FROM podem ser atualizadas rapidamente, desde que as visualizações possam ser completamente mescladas. Para obter informações sobre quais visualizações serão mescladas, consulte Referência de linguagem SQL do banco de dados Oracle .
  • Se não houver associações externas, você poderá ter seleções e associações arbitrárias na cláusula WHERE .
  • As vistas agregadas materializadas com junções externas são atualizáveis ​​rapidamente após o DML convencional e as cargas diretas, desde que apenas a tabela externa tenha sido modificada. Além disso, restrições exclusivas devem existir nas colunas de junção da tabela de junção interna. Se houver junções externas, todas as junções devem ser conectadas por AND e devem usar o operador de igualdade ( = ).
  • Para visualizações materializadas com CUBE , ROLLUP , conjuntos de agrupamentos ou concatenação deles, aplicam-se as seguintes restrições:
    • A lista SELECT deve conter um distintivo de agrupamento que pode ser uma função GROUPING_ID em todas as expressões GROUP BY ou funções GROUPING uma para cada expressão GROUP BY . Por exemplo, se a cláusula GROUP BY da exibição materializada for " GROUP BY CUBE(a, b) ", a lista SELECT deverá conter " GROUPING_ID(a, b) " ou " GROUPING(a) AND GROUPING(b) "para que a visualização materializada seja rapidamente atualizada.
    • GROUP BY não deve resultar em agrupamentos duplicados. Por exemplo, " GROUP BY a, ROLLUP(a, b) " não é atualizável rapidamente porque resulta em agrupamentos duplicados " (a), (a, b), AND (a) ".

5.3.8.7 Restrições à atualização rápida em vistas materializadas com UNION ALL

As vistas materializadas com o operador definido UNION ALL suportam a opção REFRESH FAST se as seguintes condições forem atendidas:
  • A consulta de definição deve ter o operador UNION ALL no nível superior.

    O operador UNION ALL não pode ser incorporado a uma subconsulta, com uma exceção: O UNION ALL pode estar em uma subconsulta na cláusula FROM , desde que a consulta de definição esteja no formato SELECT * FROM (exibição ou subconsulta com UNION ALL ), conforme a seguir exemplo:
      CRIAR VISTA view_with_unionall AS
     (SELECT c.rowid crid, c.cust_id, 2 anos
      FROM clientes c WHERE c.cust_last_name = 'Smith'
      UNIÃO TUDO
      SELECIONAR c.rowid crid, c.cust_id, 3 anos
      FROM clientes c WHERE c.cust_last_name = 'Jones');
    
     CRIAR VISTA MATERIALIZADA unionall_inside_view_mv
     ATUALIZE RAPIDAMENTE A DEMANDA COMO
     SELECT * FROM view_with_unionall;
    
    Observe que a visualização view_with_unionall atende aos requisitos de atualização rápida.
  • Cada bloco de consulta na consulta UNION ALL deve atender aos requisitos de uma visualização materializada atualizável rápida com agregados ou uma visualização materializada atualizável rápida com junções.

    Os logs apropriados da vista materializada devem ser criados nas tabelas, conforme necessário para o tipo correspondente de vista materializada rápida e atualizável.
    Observe que o banco de dados Oracle também permite o caso especial de uma visualização materializada de tabela única com junções somente desde que a coluna ROWID tenha sido incluída na lista SELECT e no log de visualização materializada. Isso é mostrado na consulta de definição da visualização view_with_unionall .
  • A lista SELECT de cada consulta deve incluir um marcador UNION ALL e a coluna UNION ALL deve ter um valor numérico ou sequência constante distinto em cada ramificação UNION ALL . Além disso, a coluna do marcador deve aparecer na mesma posição ordinal na lista SELECT de cada bloco de consulta. Consulte " Marcação UNION ALL e reescrita de consulta " para obter mais informações sobre marcadores UNION ALL .
  • Alguns recursos, como junções externas, consultas de exibição materializada agregada somente para inserção e tabelas remotas não são suportadas para visualizações materializadas com UNION ALL . Observe, no entanto, que as visualizações materializadas usadas na replicação, que não contêm junções ou agregados, podem ser atualizadas rapidamente quando UNION ALL ou tabelas remotas são usadas.
  • O parâmetro de inicialização de compatibilidade deve ser definido como 9.2.0 ou superior para criar uma visualização materializada atualizável rápida com UNION ALL .

Eu não quero ofender os fãs do Oracle, mas, a julgar pela lista de restrições, parece que esse mecanismo não foi escrito no caso geral usando algum tipo de modelo, mas milhares de indianos, onde todos tinham permissão para escrever seu próprio segmento, e cada um deles podia e fez. Usar esse mecanismo para lógica real é como caminhar em um campo minado. A qualquer momento, você pode obter uma mina, atingindo uma das limitações não óbvias. Como isso funciona também é um problema separado, mas está fora do escopo deste artigo.

Microsoft SQL Server

Requisitos Adicionais


Além das opções SET e dos requisitos de função determinística, os seguintes requisitos devem ser atendidos:
  • O usuário que executa CREATE INDEX deve ser o proprietário da visualização.
  • Quando você cria o índice, a opção IGNORE_DUP_KEY deve ser definida como OFF (a configuração padrão).
  • As tabelas devem ser referenciadas por nomes de duas partes, esquema . nome da tabela na definição da visualização.
  • As funções definidas pelo usuário mencionadas na visualização devem ser criadas usando a opção WITH SCHEMABINDING .
  • Quaisquer funções definidas pelo usuário mencionadas na visualização devem ser referenciadas por nomes de duas partes, <schema> . <função> .
  • A propriedade de acesso a dados de uma função definida pelo usuário deve ser NO SQL e a propriedade de acesso externo deve ser NO .
  • As funções do Common Language Runtime (CLR) podem aparecer na lista de seleção da exibição, mas não podem fazer parte da definição da chave de índice em cluster. As funções CLR não podem aparecer na cláusula WHERE da exibição ou na cláusula ON de uma operação JOIN na exibição.
  • As funções e métodos do CLR dos tipos definidos pelo usuário do CLR usados ​​na definição da visualização devem ter as propriedades configuradas conforme mostrado na tabela a seguir.
    PropriedadeNota
    DETERMINÍSTICO = VERDADEIRODeve ser declarado explicitamente como um atributo do método Microsoft .NET Framework.
    PRECISO = VERDADEIRODeve ser declarado explicitamente como um atributo do método .NET Framework.
    ACESSO DE DADOS = SEM SQLDeterminado pela configuração do atributo DataAccess como DataAccessKind.None e SystemDataAccess como SystemDataAccessKind.None.
    ACESSO EXTERNO = NÃOO padrão desta propriedade é NO para rotinas CLR.
  • A visualização deve ser criada usando a opção WITH SCHEMABINDING .
  • A visualização deve fazer referência apenas às tabelas base que estão no mesmo banco de dados que a visualização. A visualização não pode fazer referência a outras visualizações.
  • A instrução SELECT na definição de exibição não deve conter os seguintes elementos Transact-SQL:
    COUNTFunções ROWSET ( OPENDATASOURCE , OPENQUERY , OPENROWSET E OPENXML )OUTER ( LEFT , RIGHT ou FULL )
    Tabela derivada (definida especificando uma SELECT na cláusula FROM )Auto-junçõesEspecificando colunas usando SELECT * ou SELECT <table_name>.*
    DISTINCTSTDEV , STDEVP , VAR , VARP ou AVGExpressão de tabela comum (CTE)
    colunas float 1 , texto , ntext , imagem , XML ou transmissão de arquivosSubconsultaCláusula OVER , que inclui funções de janela agregadas ou de classificação
    Predicados de texto completo ( CONTAINS , FREETEXT )Função SUM que referencia uma expressão anulávelORDER BY
    Função agregada definida pelo usuário CLRTOPROLLUP CUBE , ROLLUP ou GROUPING SETS
    MIN , MAXOperadores UNION , EXCEPT ou INTERSECTTABLESAMPLE
    Variáveis ​​de tabelaOUTER APPLY ou CROSS APPLYPIVOT , UNPIVOT
    Conjuntos de colunas esparsasInline (TVF) ou funções com valor de tabela de múltiplas instruções (MSTVF)OFFSET
    CHECKSUM_AGG

    1 A exibição indexada pode conter colunas flutuantes ; no entanto, essas colunas não podem ser incluídas na chave de índice em cluster.
  • Se GROUP BY estiver presente, a definição VIEW deve conter COUNT_BIG(*) e não deve conter HAVING . Essas restrições GROUP BY são aplicáveis ​​apenas à definição de exibição indexada. Uma consulta pode usar uma exibição indexada em seu plano de execução, mesmo que não atenda a essas restrições GROUP BY .
  • Se a definição de exibição contiver uma cláusula GROUP BY , a chave do índice clusterizado exclusivo poderá fazer referência apenas às colunas especificadas na cláusula GROUP BY .

Aqui você pode ver que os índios não foram atraídos, como decidiram fazer de acordo com o esquema "faremos pouco, mas bom". Ou seja, eles têm mais minas em campo, mas sua localização é mais transparente. A coisa mais angustiante é essa limitação:
A visualização deve fazer referência apenas às tabelas base que estão no mesmo banco de dados que a visualização. A visualização não pode fazer referência a outras visualizações.

Em nossa terminologia, isso significa que uma função não pode acessar outra função materializada. Isso corta toda a ideologia pela raiz.
Além disso, essa limitação (e mais adiante no texto) reduz bastante os casos de uso:
A instrução SELECT na definição de exibição não deve conter os seguintes elementos Transact-SQL:
COUNTFunções ROWSET ( OPENDATASOURCE , OPENQUERY , OPENROWSET E OPENXML )OUTER ( LEFT , RIGHT ou FULL )
Tabela derivada (definida especificando uma SELECT na cláusula FROM )Auto-junçõesEspecificando colunas usando SELECT * ou SELECT <table_name>.*
DISTINCTSTDEV , STDEVP , VAR , VARP ou AVGExpressão de tabela comum (CTE)
colunas float 1 , texto , ntext , imagem , XML ou transmissão de arquivosSubconsultaCláusula OVER , que inclui funções de janela agregadas ou de classificação
Predicados de texto completo ( CONTAINS , FREETEXT )Função SUM que referencia uma expressão anulávelORDER BY
Função agregada definida pelo usuário CLRTOPROLLUP CUBE , ROLLUP ou GROUPING SETS
MIN , MAXOperadores UNION , EXCEPT ou INTERSECTTABLESAMPLE
Variáveis ​​de tabelaOUTER APPLY ou CROSS APPLYPIVOT , UNPIVOT
Conjuntos de colunas esparsasInline (TVF) ou funções com valor de tabela de múltiplas instruções (MSTVF)OFFSET
CHECKSUM_AGG

JUNTAS EXTERIORES, UNIÃO, ORDEM POR e outros são proibidos. Talvez fosse mais fácil indicar o que pode ser usado do que o que não é. A lista provavelmente seria muito menor.

Resumindo: um enorme conjunto de restrições em cada DBMS (observo comercial) versus nenhum (com exceção de um lógico e não técnico) na tecnologia LGPL. No entanto, deve-se notar que implementar esse mecanismo na lógica relacional é um pouco mais complicado do que no funcional descrito.

Implementação


Como isso funciona? O PostgreSQL é usado como uma "máquina virtual". Dentro, existe um algoritmo complexo que cria consultas. Aqui está o código fonte . E não há apenas um grande conjunto de heurísticas com vários ifs. Portanto, se você tiver alguns meses para estudar, poderá tentar entender a arquitetura.

Funciona eficientemente? Efetivamente o suficiente. Infelizmente, provar isso é difícil. Só posso dizer que, se você considerar os milhares de solicitações que estão em aplicativos grandes, em média, elas são mais eficazes do que um bom desenvolvedor. Um excelente programador de SQL pode escrever qualquer consulta com mais eficiência, mas com mil consultas, ele simplesmente não terá motivação nem tempo para fazer isso. A única coisa que posso dar agora como evidência de eficácia é que, com base na plataforma construída neste DBMS, vários projetos de sistemas ERP funcionam nos quais existem milhares de funções MATERIALIZED diferentes, com milhares de usuários e bancos de dados terrabytes com centenas de milhões de registros trabalhando em um servidor de processador duplo comum. No entanto, qualquer pessoa pode testar / refutar a eficácia baixando a plataforma e o PostgreSQL, permitindo o log de consultas SQL e tentando alterar a lógica e os dados.

Nos artigos a seguir, também falarei sobre como você pode suspender restrições de funções, trabalhar com sessões de alteração e muito mais.

Source: https://habr.com/ru/post/pt459066/


All Articles