O SQL tem sido a língua franca para análise de dados estruturados por várias décadas, e temos feito muito trabalho nos últimos anos para suportar o ANSI SQL e as várias extensões para tornar o SQL mais agradável de usar no Databricks. Hoje, estamos animados para anunciar a sintaxe de pipe SQL, a maior extensão que fizemos nos últimos anos para tornar o SQL dramaticamente mais fácil de escrever e entender, de uma maneira totalmente compatível com versões anteriores.
Um dos principais desafios no próprio SQL até agora reside na ordenação da "lógica". Ao escrever uma consulta, muitos autores pensam em termos dos seguintes passos lógicos: identificar a lista de tabelas para consultar, juntá-las, filtrar as linhas indesejadas e, finalmente, agregar. Essa ordenação lógica pode ser expressa da seguinte maneira:
A consulta SQL para essas etapas seria assim:
Em vez de escrever as etapas em ordem (1, 2, 3) devemos escrevê-las na ordem (3, 2, 1). Isso é confuso e o problema só se agrava à medida que adicionamos mais lógica e etapas a cada consulta.
Em contraste, vamos pensar sobre DataFrames. Uma grande fonte da popularidade original do Apache Spark entre os cientistas de dados é a poderosa capacidade de suas APIs DataFrame em Scala e Python. Os programas podem aplicar isso para expressar sua lógica em uma ordem natural de etapas. Partindo da tabela de origem, os usuários podem encadear operações independentes e compostas uma após a outra, facilitando a construção de transformações de dados complexas em uma sequência clara e intuitiva.
Este design promove a legibilidade e simplifica a depuração, mantendo a flexibilidade. É uma das principais razões pelas quais a Databricks conquistou seu enorme crescimento na indústria até agora no espaço de gerenciamento de dados, e esse ímpeto só continua a aumentar hoje.
Veja como essa mesma lógica se parece em DataFrames PySpark:
Essa abordagem suporta a iteração flexível de ideias. Sabemos que os dados de origem existem em algum arquivo, então podemos começar imediatamente criando um DataFrame que representa esses dados como uma relação. Depois de pensar um pouco, percebemos que queremos filtrar as linhas pela coluna de string. OK, então podemos adicionar um passo .filter ao final do DataFrame anterior. Ah, e queremos calcular uma projeção no final, então adicionamos isso ao final da sequência.
Muitos desses usuários desejam que o SQL se comporte de maneira mais semelhante a linguagens de dados modernas como esta. Historicamente, isso não era possível, e os usuários tinham que escolher um modo de pensar ou outro.
Avançando para hoje: agora é possível ter o melhor dos dois mundos! A sintaxe Pipe torna o SQL mais fácil de escrever, ler e estender posteriormente, e nos liberta dessa confusão, permitindo-nos simplesmente usar as mesmas etapas na ordem em que pensamos nelas.
Na conferência VLDB 2024, o Google publicou um artigo industrial propondo isso como um novo padrão. Engenheiros de processamento de consultas implementaram essa funcionalidade e a habilitaram por padrão no Apache Spark 4.0 (documentação) e Databricks Runtime 16.2 (documentação) em diante. É compatível com a sintaxe SQL regular: os usuários podem escrever consultas inteiras usando esta sintaxe, apenas certas subconsultas, ou qualquer combinação útil.
O artigo industrial fornece a consulta 13 do benchmark TPC-H como o primeiro exemplo:
Usando a sintaxe pipe para expressar a mesma lógica, aplicamos operadores em uma sequência do início ao fim com qualquer ordenação arbitrária:
Com SQL regular, quando queremos coletar linhas em grupos com base em valores de coluna ou expressão, adicionamos uma cláusula GROUP BY ao final da consulta SQL em construção. As agregações a serem realizadas permanecem presas lá no início da consulta na lista SELECT e cada expressão agora deve ser:
Qualquer item SELECT que não atenda a uma dessas categorias gerará algum erro como “a expressão X apareceu na lista SELECT, mas não foi agrupada ou agregada.”
As regras da cláusula WHERE também mudam:
A sintaxe Pipe resolve isso separando cada operação de agregação (com possível agrupamento) em uma etapa dedicada que pode ser aplicada a qualquer momento. Apenas expressões com funções agregadas podem aparecer dentro desta etapa, e funções agregadas não podem aparecer dentro das etapas |> SELECT. Se o autor do SQL esquecer qualquer um desses invariantes, as mensagens de erro resultantes são muito claras e fáceis de entender.
Também não há mais necessidade de repetir as expressões de agrupamento, já que podemos simplesmente escrevê-las em uma única cláusula GROUP BY.
Vamos olhar para o exemplo anterior com uma agregação anexada ao final, que retorna uma tabela de resultados com duas colunas L, M:
O SQL regular geralmente exige que as cláusulas apareçam em uma ordem específica, sem repetição. Se quisermos aplicar mais operações no resultado de uma consulta SQL, a maneira de fazer isso é usar uma subconsulta de tabela onde envolvemos a consulta original entre parênteses e a usamos na cláusula FROM de uma consulta envolvente. A consulta no início deste post mostra um exemplo simples disso.
Note que essa aninhamento pode ocorrer um número arbitrário de vezes. Por exemplo, aqui está a consulta TPC-DS 23:
Está ficando confuso e mais difícil de ler com todos os níveis de parênteses e indentação!
Por outro lado, com a sintaxe SQL pipe, não há necessidade de subconsultas de tabela. Como os operadores de pipe podem aparecer em qualquer ordem, podemos simplesmente adicionar novos ao final a qualquer momento, e todas as etapas ainda funcionam da mesma maneira.
A sintaxe pipe reestrutura como os autores escrevem, leem e estendem o SQL. Pode parecer um desafio mudar do pensamento de como o SQL regular funciona para esse novo paradigma. Você pode até ter um grande corpo de consultas SQL existentes escritas anteriormente que você é responsável por manter e possivelmente estender posteriormente. Como podemos fazer isso funcionar com duas sintaxes SQL?
Felizmente, isso não é um problema com nossa nova sintaxe SQL. É totalmente interoperável com o SQL regular, onde qualquer consulta (ou subconsulta de tabela) pode aparecer usando qualquer sintaxe. Podemos começar a escrever novas consultas usando a sintaxe SQL pipe e manter as anteriores, se necessário. Podemos até começar a substituir subconsultas de tabela de nossas consultas anteriores pela nova sintaxe e manter tudo o resto igual, como atualizar apenas parte do TPC-H Q13 desde o início deste post:
Como os operadores SQL pipe podem seguir qualquer consulta válida, também é possível começar a anexá-los a consultas SQL regulares existentes. Por exemplo:
A sintaxe SQL pipe está pronta para você testar na versão 16.2 e posteriores do Databricks Runtime. Ou baixe o Apache Spark 4.0 e experimente no mundo open source. A sintaxe está de acordo com o Pipe Syntax in SQL artigo industrial, então a nova sintaxe será portável com o Google BigQuery, bem como o projeto open source ZetaSQL.
Esta sintaxe também está começando a gerar burburinho na comunidade e aparecer em outros lugares, aumentando a portabilidade agora e ao longo do tempo.
Dê uma chance e experimente os benefícios de tornar as consultas SQL mais simples de escrever para usuários novos e experientes, e facilite a legibilidade e extensibilidade futuras, reduzindo a incidência de subconsultas complexas em favor de operadores claros e compostos.
(This blog post has been translated using AI-powered tools) Original Post