Eu pergunto porque muitas das perguntas que vejo no SQL são: "Isso é lento. Como faço para acelerar"? Ou há tutoriais dizendo "Faça desta maneira e não dessa maneira, pois é mais rápido".
Parece-me que grande parte do SQL sabe exatamente como uma expressão seria executada e, a partir desse conhecimento, escolhe estilos de expressão com melhor desempenho. Isso não corresponde a um aspecto da programação declarativa - o de deixar o sistema para decidir qual a melhor maneira de executar o cálculo, especificando apenas o que o cálculo deve produzir.
Um mecanismo SQL não deveria se importar com o uso in
, exists
ou join
se é realmente declarativo, não deveria apenas fornecer a resposta correta em tempo razoável, se possível por qualquer um dos três métodos? Este último exemplo é solicitado por este post recente, que é do tipo mencionado no meu parágrafo de abertura.
Índices
Eu acho que o exemplo mais fácil que eu poderia ter usado está relacionado à criação de um índice para uma tabela. O gumph aqui no w3schools.com até tenta explicar isso como algo invisível para o usuário que está lá por razões de desempenho. Sua descrição parece colocar índices SQL no campo não declarativo e eles são adicionados rotineiramente à mão por motivos puramente de desempenho.
É o caso deles estarem em algum lugar um banco de dados SQL ideal que seja muito mais declarativo do que todo o resto, mas porque é bom que não se ouça sobre isso?
fonte
select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)
. Deve ser trivial ver como reafirmar isso com umexists
ou umjoin
.Respostas:
SQL é teoricamente declarativo. Mas você sabe o que eles dizem sobre a diferença entre teoria e prática ...
Em sua essência, o conceito de "programação declarativa" nunca foi realmente eficaz e provavelmente nunca será até que tenhamos um compilador baseado em IA capaz de examinar o código e responder à pergunta "qual é a intenção desse código?" inteligentemente, da mesma maneira que a pessoa que o escreveu. No coração de toda linguagem declarativa há um monte de códigos imperativos tentando freneticamente resolver esse problema sem a ajuda de uma IA.
Muitas vezes, funciona surpreendentemente bem, porque os casos mais comuns são casos comuns , que as pessoas que escreveram a implementação da linguagem conheciam e encontravam boas maneiras de lidar. Mas, então, você se depara com um caso delicado que o implementador não considerou e vê o desempenho diminuir rapidamente, à medida que o intérprete é forçado a levar o código muito mais literalmente e manipulá-lo de maneira menos eficiente.
fonte
I rarely hit an edge case in any of them that couldn't be solved within the framework.
Sim, esse é o ponto: ter que descobrir uma maneira de resolvê-los dentro da estrutura, porque a estrutura não é inteligente o suficiente para resolvê-la da maneira que você a declarou originalmente.Eu estava pensando nisso alguns dias atrás, após uma otimização do SQL. Acho que podemos concordar que SQL é uma "linguagem declarativa" na definição da Wikipedia:
Se você pensa quantas coisas são feitas atrás das cortinas (olhando as estatísticas, decidindo se um índice é útil, indo para uma junção aninhada, mesclada ou hash, etc. etc), devemos admitir que fornecemos apenas um nível alto lógica e o banco de dados cuidou de toda a lógica do fluxo de controle de baixo nível.
Também nesse cenário, algumas vezes o otimizador de banco de dados precisa de algumas "dicas" do usuário para fornecer os melhores resultados.
Outra definição comum de linguagem "declarativa" é (não consigo encontrar uma fonte autorizada):
Se aceitarmos essa definição, encontraremos os problemas descritos pelo OP.
A primeira questão é que o SQL nos fornece várias maneiras equivalentes de definir "o mesmo resultado". Provavelmente, esse é um mal necessário: quanto mais poder expressivo dermos a uma linguagem, maior a probabilidade de haver maneiras diferentes de expressar a mesma coisa.
Como exemplo, fui solicitado uma vez a otimizar esta consulta:
Como os tipos eram muito menores que o cliente e havia um índice na
cust_type
tabela de clientes, consegui uma grande melhoria reescrevendo-o como:Nesse caso específico, quando perguntei ao desenvolvedor o que ele queria alcançar, ele me disse: "Eu queria todos os tipos de clientes para os quais tinha pelo menos um cliente"; aliás, é exatamente assim que a consulta do otimizador pode ser descrita.
Portanto, se eu poderia encontrar uma consulta equivalente e mais eficiente, por que o otimizador não pode fazer o mesmo?
Meu melhor palpite é que é por duas razões principais:
SQL expressa lógica:
Como o SQL expressa a lógica de alto nível, realmente queremos que o otimizador "nos engane" e a nossa lógica? Eu gritava entusiasticamente "sim" se não fosse por todas as vezes que eu tive que forçar o otimizador a escolher o caminho de execução mais eficiente. Eu acho que a idéia poderia ser permitir que o otimizador faça o melhor (também revise nossa lógica), mas nos dê um "mecanismo de dica" para ajudar quando algo ficar louco (seria como ter a roda + freios um carro autônomo).
Mais opções = mais tempo
Mesmo o melhor otimizador de RDBMS não testa TODOS os caminhos de execução possíveis, pois devem ser muito rápidos: quão bom seria otimizar uma consulta de 100ms a 10ms se eu precisar gastar cada 100ms escolhendo o melhor caminho? E isso é com o otimizador respeitando nossa "lógica de alto nível". Se ele também testar todas as consultas SQL equivalentes, o tempo do otimizador poderá aumentar várias vezes.
Outro bom exemplo de reescrita de consulta que nenhum RDBMS é realmente capaz de fazer é (a partir desta postagem interessante no blog )
pode ser escrito como este (funções analíticas necessárias)
fonte