
Na anterior Eu descrevi o conceito e a implementação de um banco de dados baseado em funções, em vez de tabelas e campos, como nos bancos de dados relacionais. Foram apresentados muitos exemplos que demonstram as vantagens dessa abordagem em relação à clássica. Muitos acharam que esses exemplos não eram suficientemente convincentes.
Neste artigo, mostrarei como tal conceito permite equilibrar rapidamente e de forma conveniente a gravação e a leitura em um banco de dados sem qualquer alteração na lógica de funcionamento. Funcionalidades semelhantes foram tentadas em sistemas de gerenciamento de banco de dados comerciais modernos (particularmente, Oracle e Microsoft SQL Server). No final do artigo, demonstrarei que o que eles conseguiram não foi, para dizer o mínimo, muito satisfatório.
Descrição
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 seu salário total.
Em um banco de dados funcional, isso se pareceria com:
CLASS Departamento ‘Departamento’;
nome ‘Nome’ = STRING DE DADOS[100] (Departamento);
CLASS Employee 'Funcionário';
department 'Departamento' = DATA Department (Employee);
salary 'Salário' = DATA NUMERIC[10,2] (Employee);
countEmployees 'Número de funcionários' (Department d) =
GROUP SUM 1 IF department(Employee e) = d;
salarySum 'Salário total' (Department d) =
GROUP SUM salary(Employee e) IF department(e) = d;
SELECT name(Department d), countEmployees(d), salarySum(d);
A complexidade da execução dessa consulta em qualquer SGBD será equivalente a O(número de funcionários), pois para esse cálculo é necessário escanear toda a tabela de funcionários e, em seguida, agrupá-los por departamento. Também haverá um pequeno acréscimo (considerando que há muito mais funcionários do que departamentos) dependendo do plano escolhido. O(log número de funcionários) ou O(número de departamentos) para agrupamento e outros.
É evidente que os custos de execução podem variar entre diferentes SGBDs, mas a complexidade não mudará de forma alguma.
Na implementação proposta, o SGBD funcional criará uma subconsulta que calculará os valores necessários por departamento e, em seguida, fará um JOIN com a tabela de departamentos para obter o nome. No entanto, ao declarar cada função, há a possibilidade de especificar um marcador especial MATERIALIZED. O sistema criará automaticamente o campo correspondente para cada uma dessas funções. Quando o valor da função for alterado, o valor do campo também será alterado na mesma transação. Ao acessar essa função, a consulta será feita diretamente ao campo pré-calculado.
Em particular, se você definir MATERIALIZED para as funções countEmployees e salarySum, dois campos serão adicionados à tabela da lista de departamentos, onde serão armazenados o número de funcionários e seus salários totais. A qualquer alteração nos funcionários, seus salários ou na afiliação aos departamentos, o sistema atualizará automaticamente os valores desses campos. A consulta mencionada acima fará referência diretamente a esses campos e será executada em O(número de departamentos).
Quais são as restrições? Apenas uma: essa função deve ter um número finito de valores de entrada, para os quais seu valor esteja definido. Caso contrário, não será possível construir uma tabela que armazene todos os seus valores, já que não pode haver uma tabela com um número infinito de linhas.
Exemplo:
employeesCount ‘Número de funcionários com salário > N’ (Departamento d, NUMERIC[10,2] N) =
AGRUPAR SOMA salário(Funcionário e) SE departamento(e) = d E salário(e) > N;
Essa função é definida para um número infinito de valores do número N (por exemplo, qualquer valor negativo é adequado). Portanto, não se pode definir MATERIALIZED para ela. Assim, essa é uma restrição lógica, e não técnica (ou seja, não porque não conseguimos implementá-la). De resto — nenhuma restrição. Você pode usar agrupamentos, ordenações, AND e OR, PARTITION, recursão, etc.
Por exemplo, na tarefa 2.2 do artigo anterior, você pode definir MATERIALIZED para ambas as funções:
comprou 'Comprou' (Cliente c, Produto p, INTEIRO y) =
SOMA DO GRUPO soma(Detalhe d) SE
cliente(pedido(d)) = c E
produto(d) = p E
extrairAno(data(pedido(d))) = y MATERIALIZADO;
avaliação 'Avaliação' (Cliente c, Produto p, INTEIRO y) =
SOMA PARTIDA 1 ORDEM DESC comprado(c, p, y), p POR c, y MATERIALIZADO;
SELECIONE nomeContato(Cliente c), nome(Produto p) ONDE avaliação(c, p, 1997) < 3;
O sistema criará automaticamente uma tabela com chaves de tipo Cliente, Produto e INTEGER, adicionará dois campos a ela e atualizará os valores dos campos em quaisquer alterações. Ao acessar essas funções posteriormente, não haverá cálculos, mas sim leituras dos valores dos campos correspondentes.
Com esse mecanismo, é possível, por exemplo, eliminar recursões (CTE) nas consultas. Em particular, consideremos grupos que formam uma árvore através da relação filho/pai (cada grupo tem uma referência ao seu pai):
pai = DATA Group (Grupo);
Na base de dados funcional, a lógica de recursões pode ser definida da seguinte forma:
nível (Grupo filho, Grupo pai) = RECURSÃO 1l SE filho É Grupo E pai == filho
PASSO 2l SE pai == pai($parent);
éPai (Grupo filho, Grupo pai) = VERDADEIRO SE nível(filho, pai) MATERIALIZADO;
Como para a função isParent está marcado como MATERIALIZED, uma tabela será criada com duas chaves (grupos), onde o campo isParent será verdadeiro apenas se a primeira chave for descendente da segunda. O número de registros nesta tabela será igual ao número de grupos, multiplicado pela profundidade média da árvore. Se, por exemplo, for necessário contar o número de descendentes de um grupo específico, pode-se chamar essa função:
childrenCount (Grupo g) = GRUPO SOMA 1 SE isParent(Grupo child, g);
Não haverá CTE na consulta SQL. Em vez disso, haverá um simples GROUP BY.
Com esse mecanismo, também é fácil fazer a desnormalização da base de dados, se necessário:
CLASS Order 'Pedido';
date 'Data' = DATA DATE (Pedido);
CLASS OrderDetail 'Linha do pedido';
order 'Pedido' = DATA Order (OrderDetail);
date 'Data' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED;
Ao chamar a função date para a linha do pedido, a leitura será feita da tabela com as linhas de pedidos para o campo que possui índice. Ao alterar a data do pedido, o sistema recalculará automaticamente a data desnormalizada na linha.
Vantagens
Para que serve todo esse mecanismo? Em SGBDs clássicos, sem reescrever as consultas, o desenvolvedor ou DBA pode apenas modificar índices, determinar estatísticas e sugerir ao planejador de consultas como executá-los (e os HINTs existem apenas em SGBDs comerciais). Por mais que tentem, não conseguirão executar a primeira consulta do artigo em O (número de departamentos) sem modificar as consultas e adicionar gatilhos. Já no esquema proposto, na fase de desenvolvimento, pode-se não se preocupar com a estrutura de armazenamento de dados e quais agregações usar. Tudo isso pode ser facilmente alterado em tempo real durante a operação.
Na prática, isso parece da seguinte forma. Algumas pessoas desenvolvem diretamente a lógica com base na tarefa proposta. Elas não entendem nada sobre algoritmos e suas complexidades, nem sobre planos de execução, nem sobre tipos de junção, nem sobre qualquer outro aspecto técnico. Essas pessoas são mais analistas de negócios do que desenvolvedores. Depois, tudo isso vai para teste ou produção. A gravação de consultas longas é ativada. Quando uma consulta longa é detectada, outras pessoas (mais técnicas — essencialmente DBA) decidem ativar a MATERIALIZED em alguma função intermediária. Isso desacelera um pouco a gravação (já que exige a atualização de um campo adicional na transação). No entanto, acelera significativamente não apenas essa consulta, mas todas as outras que utilizam essa função. Ao mesmo tempo, a decisão sobre qual função materializar é relativamente fácil de tomar. Dois parâmetros principais: o número de valores de entrada possíveis (exatamente esse será o número de registros na tabela correspondente) e quão frequentemente ela é usada em outras funções.
Análogos
Nos sistemas de gerenciamento de banco de dados comerciais modernos, existem mecanismos semelhantes: MATERIALIZED VIEW com FAST REFRESH (Oracle) e INDEXED VIEW (Microsoft SQL Server). No PostgreSQL, a MATERIALIZED VIEW não consegue ser atualizada em transações, apenas sob demanda (e com restrições bastante severas), portanto, não a consideramos. Mas elas têm alguns problemas que limitam significativamente seu uso.
Primeiro, a materialização só pode ser ativada se você já tiver criado uma VIEW normal. Caso contrário, será necessário reescrever as demais consultas que se referem à nova apresentação criada para utilizar essa materialização. Ou deixar tudo como está, mas isso, no mínimo, será ineficiente se houver dados que já foram pré-calculados, mas muitas consultas nem sempre os utilizam, mas os recalculam.
Em segundo lugar, elas têm uma quantidade enorme de restrições:
Oracle
5.3.8.4 Restrições Gerais sobre Atualização Rápida
A consulta definidora da view materializada é restrita da seguinte forma:
- A view materializada não deve conter referências a expressões não repetitivas, como
SYSDATEeROWNUM.- A view materializada não deve conter referências a
RAWouLONGRAWtipos de dados.- Não pode conter uma
SELECTsubconsulta em lista.- Não pode conter funções analíticas (por exemplo,
RANK) naSELECTcláusula.- Não pode referenciar uma tabela na qual um
XMLIndexíndice está definido.- Não pode conter uma
MODELcláusula.- Não pode conter uma
HAVINGcláusula com uma subconsulta.- Não pode conter consultas aninhadas que tenham
ANY,ALL, ouNOTEXISTS.- Não pode conter uma
[START WITH …] CONNECT BYcláusula.- Não pode conter várias tabelas de detalhes em diferentes sites.
ATIVADOCOMMITVisões materializadas não podem ter tabelas de detalhes remotas.- Visões materializadas aninhadas devem ter um join ou agregação.
- Visões de junção materializadas e visões de agregação materializadas com um
AGRUPAMENTOPORcláusula não pode selecionar de uma tabela organizada por índice.5.3.8.5 Restrições sobre Atualização Rápida em Visões Materializadas com Somente Joins
Definindo consultas para visões materializadas com somente joins e sem agregações, temos as seguintes restrições sobre atualização rápida:
- Todas as restrições de ««.
- Elas não podem ter
AGRUPAMENTOPORcláusulas ou agregações.- Rowids de todas as tabelas na
FROMlista devem aparecer naSELECTlista da consulta.- Os logs de visão materializada devem existir com rowids para todas as tabelas base na
FROMlista da consulta.- Você não pode criar uma visão materializada atualizável rapidamente a partir de várias tabelas com joins simples que incluam uma coluna de tipo objeto na
SELECTdeclaração.Além disso, o método de atualização que você escolher não será otimamente eficiente se:
- A consulta definidora usa um outer join que se comporta como um inner join. Se a consulta definidora contiver tal join, considere reescrever a consulta definidora para conter um inner join.
- A
SELECTlista da visão materializada contém expressões em colunas de várias tabelas.5.3.8.6 Restrições sobre Atualização Rápida em Visões Materializadas com Agregações
Definindo consultas para visões materializadas com agregações ou joins, temos as seguintes restrições sobre atualização rápida:
- Todas as restrições de ««.
A atualização rápida é suportada para ambas as
ATIVADOCOMMITeATIVADODEMANDAvisões materializadas, 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:
- Contém todas as colunas da tabela referenciada na visão materializada.
- Especificar com
ROWIDeINCLUINDONOVAVALUES.- Especificar a
SEQUÊNCIAcláusula se a tabela for esperada para ter uma mistura de inserções/carregamentos diretos, exclusões e atualizações.- Somente
SOMA,CONTAGEM,AVG,STDDEV,VARIÂNCIA,MINeMÁXIMOsão suportados para atualização rápida.CONTAGEM(*)deve ser especificado.- Funções de agregação devem ocorrer apenas como a parte mais externa da expressão. Ou seja, agregações como
MÉDIA(MÉDIA(x))ouMÉDIA(x)+MÉDIA(x)não são permitidas.- Para cada agregação como
MÉDIA(expr), a correspondenteCONTAGEM(expr)deve estar presente. A Oracle recomenda queSOMA(expr)seja especificado.- Se
VARIÂNCIA(expr)ouSTDDEV(expr) é especificado,CONTAGEM(expr)eSOMA(expr)deve ser especificado. A Oracle recomenda queSOMA(expr*expr)seja especificado.- A
SELECTcoluna na consulta definidora não pode ser uma expressão complexa com colunas de várias tabelas base. Uma possível solução é usar uma visão materializada aninhada.- A
SELECTa lista deve conter todasAGRUPAMENTOPORas colunas.- A visão materializada não é baseada em uma ou mais tabelas remotas.
- Se você usar um
CARACTEREtipo de dado nas colunas de filtro de um log de visão materializada, os conjuntos de caracteres do site mestre e da visão materializada devem ser os mesmos.- Se a visão materializada tiver um dos seguintes, então a atualização rápida é suportada apenas em inserções DML convencionais e carregamentos diretos.
- Visões materializadas com
MINouMÁXIMOagregações- Visões materializadas que têm
SOMA(expr)mas nãoCONTAGEM(expr)- Visões materializadas sem
CONTAGEM(*)Tal visão materializada é chamada de visão materializada apenas de inserção.
- Uma visão materializada com
MÁXIMOouMINé atualizável rapidamente após deleções ou declarações DML mistas se não tiver umWHEREcláusula.
A atualização rápida de máximo/mínimo após deleção ou DML misto não tem o mesmo comportamento que o caso de apenas inserção. Ela exclui e recomputa os valores máximo/mínimo para os grupos afetados. Você precisa estar ciente de seu impacto na performance.- Visões materializadas com visões nomeadas ou subconsultas na
FROMcláusula podem ser atualizadas rapidamente, desde que as visões possam ser completamente mescladas. Para informações sobre quais visões serão mescladas, consulte .- Se não houver joins externos, você pode ter seleções e joins arbitrários na
WHEREcláusula.- As visões agregadas materializadas com junções externas são atualizáveis rapidamente após DML convencional e cargas diretas, desde que apenas a tabela externa tenha sido modificada. Além disso, devem existir restrições exclusivas nas colunas de junção da tabela interna. Se houver junções externas, todas as junções devem estar conectadas por
Ee devem usar a igualdade (=) operador.- Para visões materializadas com
CUBE,ROLLUP, conjuntos de agrupamento ou concatenação deles, as seguintes restrições se aplicam:
- A
SELECTa lista deve conter um diferenciador de agrupamento que pode ser umGROUPING_IDfunção em todasAGRUPAMENTOPORas expressões ouGROUPINGfunções uma para cadaAGRUPAMENTOPORexpressão. Por exemplo, se aAGRUPAMENTOPORcláusula da visão materializada é «AGRUPAMENTOPORCUBE(a, b)«, então aSELECTlista deve conter «GROUPING_ID(a, b)» ou «GROUPING(a)EGROUPING(b)» para que a visão materializada seja atualizável rapidamente.AGRUPAMENTOPORnão deve resultar em grupos duplicados. Por exemplo, «GROUP BY a, ROLLUP(a, b)» não é atualizável rapidamente porque resulta em grupos duplicados «(a), (a, b), E (a)«.5.3.8.7 Restrições na Atualização Rápida em Visões Materializadas com UNION ALL
As visões materializadas com o
UNIONALLoperador de conjunto suportam aopção deATUALIZAÇÃORÁPIDA
- se as seguintes condições forem atendidas:
UNIONALLA consulta de definição deve ter oA
UNIONALLoperador no nível superior.UNIONALLo operador não pode ser embutido dentro de uma subconsulta, com uma exceção: oFROMpode estar em uma subconsulta nacláusula desde que a consulta de definição seja da formaSELECT * FROMUNIONALL(visão ou subconsulta com) como no seguinte exemplo:CREATE VIEW view_with_unionall AS (SELECT c.rowid crid, c.cust_id, 2 umarker FROM customers c WHERE c.cust_last_name = 'Smith' UNION ALL SELECT c.rowid crid, c.cust_id, 3 umarker FROM customers c WHERE c.cust_last_name = 'Jones');CREATE MATERIALIZED VIEW unionall_inside_view_mv REFRESH FAST ON DEMAND AS SELECT * FROM view_with_unionall;
Observe que a visãoview_with_unionall- satisfa os requisitos para atualização rápida.
UNIONALLCada bloco de consulta naconsulta deve satisfazer os requisitos de uma visão materializada atualizável rapidamente com agregados ou uma visão materializada atualizável rapidamente com junções.
Os logs de visão materializada apropriados devem ser criados nas tabelas conforme necessário para o tipo correspondente de visão materializada atualizável rapidamente.ROWIDObserve que o Oracle Database também permite o caso especial de uma visão materializada de tabela única com junções, desde que aSELECTcoluna tenha sido incluída naObserve que a visão.- A
SELECTlista e no log de visão materializada. Isso é mostrado na consulta de definição da visãoUNIONALLa lista de cada consulta deve incluir umUNIONALLmarcador, e aUNIONALLcoluna deve ter um valor numérico ou string constante distinto em cadaSELECTramo. Além disso, a coluna de marcador deve aparecer na mesma posição ordinal naUNION ALL Marker and Query RewriteUNIONALL» para mais informações sobre- marcadores.
UNIONALLAlguns recursos, como junções externas, consultas de visão materializada de agregados apenas para inserção e tabelas remotas não são suportados para visões materializadas comUNIONALL. Observe, entretanto, que as visões materializadas usadas em replicações, que não contêm junções ou agregados, podem ser atualizadas rapidamente quando- ou tabelas remotas são usadas.
UNIONALL.
Não quero ofender os fãs da Oracle, mas com base na lista de restrições deles, parece que esse mecanismo foi escrito não de forma geral, usando algum modelo, mas por milhares de indianos, onde cada um teve a oportunidade de escrever seu próprio trecho, e cada um fez o que pôde. Usar esse mecanismo para lógica real é como andar por um campo minado. A qualquer momento, você pode ativar uma mina ao encontrar uma das restrições não óbvias. Como isso funciona também é uma questão separada, 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
CRIAR ÍNDICEdeve ser o proprietário da visão.- Ao criar o índice, a
IGNORE_DUP_KEYopção deve estar definida como DESATIVADA (configuração padrão).- As tabelas devem ser referenciadas por nomes de duas partes, schema.tablename na definição da visão.
- As funções definidas pelo usuário referenciadas na visão devem ser criadas usando a
COM VINCULAÇÃO DE ESQUEMAopção.- Qualquer função definida pelo usuário referenciada na visão deve ser referenciada por nomes de duas partes, <schema>.<função>.
- A propriedade de acesso aos dados de uma função definida pelo usuário deve ser
SEM SQL, e a propriedade de acesso externo deve serNÃO.- Funções de tempo de execução comum (CLR) podem aparecer na lista de seleção da visão, mas não podem fazer parte da definição da chave do índice clustered. Funções CLR não podem aparecer na cláusula WHERE da visão ou na cláusula ON de uma operação JOIN na visão.
- As funções CLR e os métodos de tipos definidos pelo usuário CLR usados na definição da visão devem ter as propriedades definidas conforme mostrado na tabela a seguir.
Propriedade
NoteDETERMINÍSTICO = VERDADEIRO
Deve ser declarado explicitamente como um atributo do método do Microsoft .NET Framework.PRECISO = VERDADEIRO
Deve ser declarado explicitamente como um atributo do método do .NET Framework.ACESSO A DADOS = SEM SQL
Determinado definindo o atributo DataAccess como DataAccessKind.None e o atributo SystemDataAccess como SystemDataAccessKind.None.ACESSO EXTERNO = NÃO
Essa propriedade tem como padrão NÃO para rotinas CLR.- A visão deve ser criada usando a
COM VINCULAÇÃO DE ESQUEMAopção.- A visão deve referenciar apenas tabelas base que estão no mesmo banco de dados que a visão. A visão não pode referenciar outras visões.
- A instrução SELECT na definição da visão não deve conter os seguintes elementos Transact-SQL:
CONTAGEM
Funções de conjunto de linhas (OPENDATASOURCE,OPENQUERY,OPENROWSET, EOPENXML)
JUNÇÕES(ESQUERDA,DIREITA, ouCOMPLETA)Tabela derivada (definida especificando um
SELECTdeclaração naFROMcláusula)
Auto-junções
Especificando colunas usandoSELECIONAR *ouSELECIONAR <nome_tabela>.*
DISTINCT
STDEV,STDEVP,VAR,VARP, ouAVG
Expressão de tabela comum (CTE)float1, texto, ntext, image, XML, ou filestream colunas
Subconsulta
CLÁUSULA OVER, que inclui funções de janela de classificação ou agregaçãoPredicados de texto completo (CONTÉM
FREETEXT,função que referencia uma expressão anulável)
SOMAORDEM POR
FUNÇÃO AGREGADA DEFINIDA PELO USUÁRIO CLRTOP
CONJUNTOS DE AGRUPAMENTO
CUBE,ROLLUP, ouoperadoresEXCETO
MIN,MÁXIMO
UNION,TABLESAMPLE, ouINTERSECTEXCETO
Variáveis de tabelaOUTER APPLY
CROSS APPLYouPIVOT
UNPIVOT,Conjuntos de colunas esparsasFunções definidas pelo usuário de tabela inline (TVF) ou de múltiplas instruções (MSTVF)
CHECKSUM_AGG
OFFSET
1 A visão indexada pode contercolunas; no entanto, tais colunas não podem ser incluídas na chave do índice clustered. float está presente, a definição da VISÃO deve conter
- Se
GROUP BYCOUNT_BIG(*)e não deve conter. EssasHAVINGrestrições se aplicam apenas à definição da visão indexada. Uma consulta pode usar uma visão indexada em seu plano de execução, mesmo que não satisfaça essasGROUP BYrestrições.GROUP BYSe a definição da visão contiver um- cláusula, a chave do índice clustered único pode referenciar apenas as colunas especificadas em
GROUP BY.GROUP BYcláusula.
Aqui está evidente que os indianos não foram atraídos, pois decidiram seguir o esquema de "fazemos pouco, mas bem." Ou seja, eles têm mais minas em campo, mas a sua disposição é mais transparente. O que mais desagrada é esta limitação:
A visão deve referenciar apenas tabelas base que estão no mesmo banco de dados que a visão. A visão não pode referenciar outras visões.
Em nossa terminologia, isso significa que a função não pode se referir a outra função materializada. Isso corta toda a ideologia pela raiz.
Além disso, esta limitação (e adiante no texto) reduz bastante as opções de uso:
A instrução SELECT na definição da visão não deve conter os seguintes elementos Transact-SQL:
CONTAGEM
Funções de conjunto de linhas (OPENDATASOURCE,OPENQUERY,OPENROWSET, EOPENXML)
JUNÇÕES(ESQUERDA,DIREITA, ouCOMPLETA)Tabela derivada (definida especificando um
SELECTdeclaração naFROMcláusula)
Auto-junções
Especificando colunas usandoSELECIONAR *ouSELECIONAR <nome_tabela>.*
DISTINCT
STDEV,STDEVP,VAR,VARP, ouAVG
Expressão de tabela comum (CTE)float1, texto, ntext, image, XML, ou filestream colunas
Subconsulta
CLÁUSULA OVER, que inclui funções de janela de classificação ou agregaçãoPredicados de texto completo (CONTÉM
FREETEXT,função que referencia uma expressão anulável)
SOMAORDEM POR
FUNÇÃO AGREGADA DEFINIDA PELO USUÁRIO CLRTOP
CONJUNTOS DE AGRUPAMENTO
CUBE,ROLLUP, ouoperadoresEXCETO
MIN,MÁXIMO
UNION,TABLESAMPLE, ouINTERSECTEXCETO
Variáveis de tabelaOUTER APPLY
CROSS APPLYouPIVOT
UNPIVOT,Conjuntos de colunas esparsasFunções definidas pelo usuário de tabela inline (TVF) ou de múltiplas instruções (MSTVF)
CHECKSUM_AGG
OFFSET
1 A visão indexada pode conter
São proibidos OUTER JOINS, UNION, ORDER BY e outros. Seria provavelmente mais simples indicar o que pode ser usado do que o que não pode. A lista provavelmente seria muito menor.
Resumindo: um enorme conjunto de restrições em cada (note que estou falando de bancos de dados comerciais) SGBD versus nenhuma (exceto uma lógica, e não técnica) na tecnologia LGPL. No entanto, vale notar que implementar esse mecanismo na lógica relacional é algo mais complicado do que na funcional funcional descrita.
Implementação
Como isso funciona? Como "máquina virtual" usa-se o PostgreSQL. Dentro dele há um algoritmo complexo que se ocupa da construção de consultas. Aqui está . E lá não é apenas um grande conjunto de heurísticas com muitos ifs. Então, se você tiver alguns meses para estudar, pode tentar entender a arquitetura.
Isso funciona de forma eficiente? De forma bastante eficiente. Infelizmente, é difícil provar isso. Só posso dizer que, se considerarmos milhares de consultas em grandes aplicativos, em média elas são mais eficientes do que as de um bom desenvolvedor. Um ótimo programador SQL pode escrever qualquer consulta de forma mais eficiente, mas em mil consultas ele simplesmente não terá nem motivação nem tempo para fazer isso. A única coisa que posso trazer agora como prova da eficiência é que na base de uma plataforma construída sobre este SGBD operam vários projetos , nos quais há milhares de diferentes funções MATERIALIZED, com milhares de usuários e bancos de dados de terabytes com centenas de milhões de registros, funcionando em um servidor comum de dois processadores. Contudo, qualquer interessado pode verificar/invalidar a eficiência, baixando e PostgreSQL, ativando o registro de consultas SQL e tentando alterar a lógica e os dados.
Nos próximos artigos, também falarei sobre como impor restrições a funções, trabalhar com sessões de mudanças e muito mais.
Fonte: habr.com
