Today, Structured Query Language é o meio padrão de manipulação e consulta de dados em bases de dados relacionais, embora com extensões proprietárias entre os produtos. A facilidade e ubiquidade do SQL levaram mesmo os criadores de muitos armazéns de dados “NoSQL” ou não relacionais, como o Hadoop, a adoptar subconjuntos de SQL ou a criar as suas próprias linguagens de consulta SQL.
Mas SQL nem sempre foi a linguagem “universal” para bases de dados relacionais. Desde o início (cerca de 1980), SQL teve certos golpes contra ela. Muitos investigadores e programadores na altura, incluindo eu, pensavam que a sobrecarga de SQL iria impedir que alguma vez fosse prática numa base de dados de produção.
Claramente, estávamos errados. Mas muitos ainda acreditam que, por toda a facilidade e acessibilidade do SQL, o preço exacto no desempenho em tempo de execução é frequentemente demasiado elevado.
H2>Histórico doSQL
Antes de haver SQL, as bases de dados tinham interfaces de programação de navegação apertadas, e tipicamente eram concebidas em torno de um esquema de rede chamado modelo de dados CODASYL. CODASYL (Committee on Data Systems Languages) era um consórcio que era responsável pela linguagem de programação COBOL (com início em 1959) e extensões de linguagem de base de dados (com início 10 anos mais tarde).
Quando se programava contra uma base de dados CODASYL, navegava-se para registos através de conjuntos, que expressavam relações de um para muitos. As bases de dados hierárquicas mais antigas apenas permitem que um registo pertença a um conjunto. As bases de dados em rede permitem que um registo pertença a vários conjuntos.
Dizer que queria listar os estudantes inscritos no CS 101. Primeiro encontrará "CS 101"
no conjunto Courses
definido pelo nome, defina que como proprietário ou pai do conjunto Enrollees
definido, encontrar o primeiro membro (ffm
) do conjunto Enrollees
, que é um conjunto Student
, e listá-la. Depois entraria num laço: Encontre o próximo membro (fnm
) e liste-o. Quando fnm
falhava, sairia do loop.
Isso pode parecer muito trabalho de scut para o programador da base de dados, mas era muito eficiente no momento da execução. Especialistas como Michael Stonebraker da Universidade da Califórnia em Berkeley e Ingres salientaram que fazer esse tipo de consulta numa base de dados CODASYL como o IDMS levou cerca de metade do tempo da CPU e menos de metade da memória como a mesma consulta numa base de dados relacional usando SQL.
Para comparação, a consulta SQL equivalente para devolver todos os estudantes no CS 101 seria algo como
SELECT student.name FROM courses, enrollees, students WHERE course.name ="CS 101"
Essa sintaxe implica uma união interna relacional (na realidade duas delas), como explicarei abaixo, e deixa de fora alguns detalhes importantes, tais como os campos utilizados para as uniões.
Bases de dados relacionais e SQL
Por que desistiria de um factor de duas melhorias na velocidade de execução e no uso de memória? Havia duas grandes razões: facilidade de desenvolvimento e portabilidade. Eu pensava que nenhuma delas era importante em 1980 em comparação com o desempenho e os requisitos de memória, mas à medida que o hardware informático melhorava e se tornava mais barato as pessoas deixaram de se preocupar com a velocidade de execução e a memória e preocupavam-se mais com o custo de desenvolvimento.
Por outras palavras, a Lei de Moore matou as bases de dados CODASYL em favor das bases de dados relacionais. Como aconteceu, a melhoria no tempo de desenvolvimento foi significativa, mas a portabilidade do SQL acabou por ser um sonho impossível.
De onde vieram o modelo relacional e o SQL? E.F. “Ted” Codd foi um cientista informático no Laboratório de Investigação IBM San Jose que elaborou a teoria do modelo relacional nos anos 60 e a publicou em 1970. A IBM foi lenta a implementar uma base de dados relacional, num esforço para proteger as receitas da sua base de dados CODASYL IMS/DB. Quando a IBM finalmente iniciou o seu projecto System R, a equipa de desenvolvimento (Don Chamberlin e Ray Boyce) não estava sob o Codd, e ignoraram o documento da linguagem relacional Alfa 1971 do Codd para conceber a sua própria linguagem, SEQUEL (Structured English Query Language). Em 1979, antes mesmo da IBM ter lançado o seu produto, Larry Ellison incorporou a língua na sua base de dados Oracle (utilizando as publicações pré-lançadas da IBM SEQUEL como sua especificação). A SEQUEL rapidamente se tornou SQL para evitar uma violação de marca registada internacional.
Os “tom-toms batendo por SQL” (como Michael Stonebraker colocou) vinham não só da Oracle e da IBM, mas também de clientes. Não era fácil contratar ou formar desenhadores e programadores de bases de dados CODASYL, pelo que a SEQUEL (e SQL) parecia muito mais atraente. SQL era tão atraente no final dos anos 80 que muitos vendedores de bases de dados agrafaram essencialmente um processador de consulta SQL em cima das suas bases de dados CODASYL, para grande consternação da Codd, que sentiu que as bases de dados relacionais tinham de ser concebidas de raiz para serem relacionais.
Uma base de dados relacional pura, tal como concebida pela Codd, é construída em tuplos agrupados em relações, consistentes com a lógica de primeira ordem dos predicados. As bases de dados relacionais do mundo real têm tabelas que contêm campos, restrições e gatilhos, e as tabelas estão relacionadas através de chaves estrangeiras. SQL é utilizada para declarar os dados a serem devolvidos, e um processador e optimizador de consultas SQL transforma a declaração SQL num plano de consultas que é executado pelo motor da base de dados.
SQL inclui uma sub-língua para definir esquemas, a linguagem de definição de dados (DDL), juntamente com uma sub-língua para modificar os dados, a linguagem de manipulação de dados (DML). Ambas têm raízes em especificações CODASYL iniciais. A terceira sub-língua em SQL declara as consultas, através da declaração SELECT
declaração e uniões relacionais.
declaração SELECTSQL
A declaração SELECT
diz ao optimizador de consultas quais os dados a retornar, quais as tabelas a consultar, quais as relações a seguir, e qual a ordem a impor aos dados retornados. O optimizador de consultas tem de descobrir por si só quais os índices a utilizar para evitar varreduras de tabelas de força bruta e conseguir um bom desempenho das consultas, a menos que a base de dados específica suporte dicas de índices.
Parte da arte do design de bases de dados relacionais depende do uso judicioso dos índices. Se se omitir um índice para uma consulta frequente, toda a base de dados pode abrandar sob cargas pesadas de leitura. Se tiver demasiados índices, toda a base de dados pode abrandar sob cargas pesadas de escrita e actualização.
Uma outra arte importante é escolher uma boa e única chave primária para cada tabela. Não só tem de considerar o impacto da chave primária nas consultas comuns, mas também a forma como irá jogar nas junções quando aparecer como uma chave estrangeira noutra tabela, e como irá afectar a localidade de referência dos dados.
No caso avançado de tabelas de bases de dados que estão divididas em diferentes volumes, dependendo do valor da chave primária, chamada de fragmentação horizontal, também tem de considerar a forma como a chave primária irá afectar a fragmentação. Dica: Quer que a tabela seja distribuída uniformemente pelos volumes, o que sugere que não quer usar carimbos de data ou inteiros consecutivos como chaves primárias.
Discussões da declaração SELECT
podem começar a ser simples, mas podem rapidamente tornar-se confusas. Considere:
SELECT * FROM Customers;
Simples, certo? Pede todos os campos e todas as filas da tabela Customers
. Suponha, contudo, que a tabela Customers
tem cem milhões de linhas e cem campos, e um dos campos é um grande campo de texto para comentários. Quanto tempo demorará a puxar para baixo todos esses dados através de uma ligação de rede de 10 megabit por segundo se cada linha contiver uma média de 1 kilobyte de dados?
Talvez se deva cortar o quanto se envia através do fio. Considere:
SELECT TOP 100 companyName, lastSaleDate, lastSaleAmount, totalSalesAmount FROM Customers
WHERE state ="Ohio" AND city ="Cleveland"
ORDER BY lastSaleDate DESCENDING;
Agora vai puxar para baixo muito menos dados. Pediu à base de dados para lhe dar apenas quatro campos, para considerar apenas as empresas em Cleveland, e para lhe dar apenas as 100 empresas com as vendas mais recentes. Para o fazer de forma mais eficiente no servidor da base de dados, no entanto, o Customers
tabela precisa de um índice em state+city
para o WHERE
e um índice sobre lastSaleDate
para as cláusulas ORDER BY
e TOP 100
.
pelo caminho, TOP 100
é válido para o SQL Server e SQL Azure, mas não para o MySQL ou Oracle. No MySQL, utilizaria LIMIT 100
após a cláusula WHERE
. No Oracle, utilizaria uma cláusula ROWNUM
como parte da cláusula WHERE
, ou seja . Infelizmente, as normas ANSI/ISO SQL (e são nove até à data, desde 1986 até 2016) só vão até ao ponto em que cada base de dados introduz as suas próprias cláusulas e características proprietárias.
SQL junta-se
Até agora, descrevi a SELECT
sintaxe para tabelas únicas. Antes de poder explicar JOIN
cláusulas, é necessário compreender chaves estrangeiras e relações entre tabelas. Explicarei isto usando exemplos em DDL, usando a sintaxe do SQL Server.
A versão curta disto é bastante simples. Cada tabela que pretende utilizar nas relações deve ter uma restrição de chave primária; esta pode ser um único campo ou uma combinação de campos definidos por uma expressão. Por exemplo:
CREATE TABLE Persons (
PersonID int NOT NULL PRIMARY KEY,
PersonName char(80),
...
Toda a tabela que precisa de se relacionar com Persons
deve ter um campo que corresponda ao Persons
chave primária, e para preservar a integridade relacional esse campo deve ter um constrangimento de chave externa. Por exemplo:
CREATE TABLE Orders (
OrderID int NOT NULL PRIMARY KEY,
...
PersonID int FOREIGN KEY REFERENCES Persons(PersonID)
);
Existem versões mais longas de ambas as afirmações que utilizam a palavra-chave CONSTRAINT
, o que permite nomear a restrição. É isso que a maioria das ferramentas de concepção de bases de dados geram.
As chaves primárias são sempre indexadas e únicas (os valores do campo não podem ser duplicados). Outros campos podem opcionalmente ser indexados. É frequentemente útil criar índices para campos chave estrangeiros e para campos que aparecem em WHERE
e ORDER BY
cláusulas, embora nem sempre, devido às potenciais despesas gerais de escritas e actualizações.
Como escreveria uma consulta que devolva todas as encomendas feitas por John Doe?
SELECT PersonName, OrderID FROM Persons
INNER JOIN Orders ON Persons.PersonID = Orders.PersonID
WHERE PersonName ="John Doe";
De facto, existem quatro tipos de JOIN
INNER
OUTER
LEFT
, e RIGHT
. O INNER JOIN
é o padrão (pode omitir a palavra INNER
), e é o que inclui apenas as linhas que contêm valores correspondentes em ambas as tabelas. Se quiser listar pessoas quer tenham ou não encomendas, usaria um LEFT JOIN
, por exemplo:
SELECT PersonName, OrderID FROM Persons
LEFT JOIN Orders ON Persons.PersonID = Orders.PersonID
ORDER BY PersonName;
Quando começa a fazer consultas que juntam mais de duas tabelas, que usam expressões, ou que coagem tipos de dados, a sintaxe pode ficar um pouco cabeluda no início. Felizmente, existem ferramentas de desenvolvimento de bases de dados que podem gerar consultas SQL correctas para si, muitas vezes arrastando e largando tabelas e campos do diagrama de esquema para um diagrama de consulta.
Procedimentos armazenados doSQL
A natureza declarativa do SELECT
declaração não o leva para onde quer ir. A maioria das bases de dados tem uma facilidade chamada procedimentos armazenados; infelizmente, esta é uma área onde quase todas as bases de dados utilizam extensões proprietárias segundo as normas ANSI/ISO SQL.
No SQL Server, o dialecto inicial para procedimentos armazenados (ou procs armazenados) era Transact-SQL, também conhecido por T-SQL; no Oracle, era PL-SQL. Ambas as bases de dados adicionaram linguagens adicionais para procedimentos armazenados, tais como C#, Java, e R. Um procedimento simples de T-SQL armazenado pode ser apenas uma versão parametrizada de uma declaração SELECT
. As suas vantagens são a facilidade de utilização e a eficiência. Os procedimentos armazenados são optimizados quando são guardados, não sempre que são executados.
Um procedimento armazenado T-SQL mais complicado pode utilizar múltiplas instruções SQL, parâmetros de entrada e saída, variáveis locais, BEGIN...END
blocos, IF...THEN...ELSE
condições, cursores (processamento linha a linha de um conjunto), expressões, tabelas temporárias, e toda uma série de outras sintaxes de procedimento. Obviamente, se a linguagem de procedimento armazenada for C#, Java, ou R, vai utilizar as funções e sintaxe dessas linguagens de procedimento. Por outras palavras, apesar do facto de que a motivação para SQL era utilizar consultas declarativas padronizadas, no mundo real vê-se muita programação de servidores de procedimentos específicos de bases de dados.
Isso não nos leva propriamente de volta aos maus velhos tempos da programação de bases de dados CODASYL (embora os cursores se aproximem), mas volta-se das ideias de que as declarações SQL devem ser padronizadas e que as preocupações de desempenho devem ser deixadas para o optimizador de consultas de bases de dados. No final, uma duplicação do desempenho é muitas vezes demasiado para deixar na tabela.
Learn SQL
Os sites listados abaixo podem ajudá-lo a aprender SQL, ou descobrir as peculiaridades de vários dialectos SQL.
- Codecademy. Aprenda SQL. Livre e interactivo. Actualização Pro disponível por uma taxa.
- Academia Khan. Introdução a SQL: Consulta e Gestão de Dados. Tutorial vídeo gratuito.
- SoloLearn. Fundamentos de SQL. Orientado para o MySQL. Grátis.
- Problemas e Soluções SQL e Exercícios SQL. Livro-texto e exercícios interactivos. Gratuito.
- SQLZoo. Um tutorial SQL interactivo desenvolvido e mantido pela Universidade Edinburgh Napier. Suporta Microsoft SQL Server, Oracle Database, MySQL, IBM DB2, e PostgreSQL. Gratuito.
- Tutorialspoint. Aprenda SQL. Apenas texto, não interactivo. Free.
- Udacidade. Introdução às Bases de Dados Relacionais. Utiliza Python e requer algum conhecimento Python. Free.
- Udemy. Cursos gratuitos incluem Introdução a Bases de Dados e Consultas SQL, Base de Dados MySQL para Principiantes, Microsoft SQL para Principiantes, Hands-on SQL para Principiantes (
SELECT
FROM
, eWHERE
), e Sachin Quickly Learns (SQL). - Academia Vertabelo. SQL Basics, Operating on Data in SQL, Creating Tables in SQL, e outros oito cursos interactivos de SQL. Alguns cursos têm test drives gratuitos, após o que pode haver uma taxa. Existem sete cursos adicionais para o Microsoft SQL Server. O sítio tem também uma ferramenta gráfica de desenho de base de dados para PostgreSQL, MySQL, Oracle Database, SQL Server, SQLite, e IBM DB2.
- W3Schools. Tutorial SQL. Grátis e disponível sem registo.
Documentação da base de dados: