Introdução
Até aqui as tabelas da série guardavam dados dentro do banco. As external tables fazem o contrário: são só metadados que apontam para dados que estão fora dele, seja em outra instância SQL Server, em Oracle, em arquivos Parquet e CSV no Azure Blob Storage, no ADLS Gen2 ou em storage compatível com S3. É a base do que a Microsoft chama de data virtualization via PolyBase: consultar sem copiar, sem ETL.
Como funciona
O PolyBase monta a consulta em quatro peças, sempre nesta ordem:
- DATABASE MASTER KEY: protege os segredos guardados no banco.
- DATABASE SCOPED CREDENTIAL: usuário e senha, SAS token ou access key do destino.
- EXTERNAL DATA SOURCE: onde estão os dados, com prefixo de conector (sqlserver://, oracle://, abs://, adls://, s3://…).
- EXTERNAL FILE FORMAT (só para arquivos) e EXTERNAL TABLE: o schema que o T-SQL enxerga.
Com PUSHDOWN = ON, filtros e agregações são executados na origem, trafegando menos dados.
Mão na massa: SQL Server consultando SQL Server
Para ficar 100% reproduzível sem conta na nuvem, vamos usar a própria instância como origem (loopback). Requisito: a feature PolyBase Query Service for External Data instalada no setup e um login SQL (autenticação mista habilitada).
-- 1. Habilita o PolyBase na instância
USE master;
GO
EXEC sp_configure 'polybase enabled', 1;
RECONFIGURE;
GO
-- 2. Banco de origem simulando um sistema externo
CREATE DATABASE DP800_Origem;
GO
USE DP800_Origem;
GO
CREATE TABLE dbo.Cliente
(
ClienteId INT NOT NULL PRIMARY KEY,
Nome NVARCHAR(100) NOT NULL,
UF CHAR(2) NOT NULL
);
INSERT INTO dbo.Cliente VALUES
(1, N'Padaria do Zé', 'SP'),
(2, N'Mercado Sol', 'RJ'),
(3, N'Tech Sul', 'RS');
GO
-- Login SQL que o PolyBase usará para ler a origem (troque a senha!)
USE master;
GO
CREATE LOGIN polybase_leitor WITH PASSWORD = 'Troque@Esta#Senha2025';
GO
USE DP800_Origem;
GO
CREATE USER polybase_leitor FOR LOGIN polybase_leitor;
ALTER ROLE db_datareader ADD MEMBER polybase_leitor;
GO
-- 3. No banco de laboratório: master key + credential
USE DP800_Lab;
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'Master@Key#DP800!';
GO
CREATE DATABASE SCOPED CREDENTIAL cred_Origem
WITH IDENTITY = 'polybase_leitor', SECRET = 'Troque@Esta#Senha2025';
GO
-- 4. External data source (TrustServerCertificate por causa do certificado autoassinado)
CREATE EXTERNAL DATA SOURCE ds_SqlOrigem
WITH
(
LOCATION = 'sqlserver://localhost',
PUSHDOWN = ON,
CREDENTIAL = cred_Origem,
CONNECTION_OPTIONS = 'TrustServerCertificate=Yes'
);
GO
-- 5. External table: o schema precisa bater com a origem
CREATE EXTERNAL TABLE dbo.ext_Cliente
(
ClienteId INT NOT NULL,
Nome NVARCHAR(100) NOT NULL,
UF CHAR(2) NOT NULL
)
WITH
(
LOCATION = 'DP800_Origem.dbo.Cliente', -- banco.schema.tabela
DATA_SOURCE = ds_SqlOrigem
);
GO
-- 6. Consultando como se fosse local (inclusive com JOIN em tabela local)
SELECT * FROM dbo.ext_Cliente WHERE UF = 'RS';
-- Cria estatística para ajudar o otimizador na external table
CREATE STATISTICS st_ext_Cliente_UF ON dbo.ext_Cliente (UF) WITH FULLSCAN;
-- 7. Metadados do que foi criado
SELECT name, location, pushdown FROM sys.external_data_sources;
SELECT name, location FROM sys.external_tables;
Mão na massa: arquivos Parquet e CSV no storage
Aqui você precisa de uma storage account sua. Troque <conta>, <container> e o SAS token pelos seus valores.
USE DP800_Lab;
GO
-- Credential com SAS token (sem o '?' inicial)
CREATE DATABASE SCOPED CREDENTIAL cred_Blob
WITH IDENTITY = 'SHARED ACCESS SIGNATURE',
SECRET = '<seu-sas-token>';
GO
CREATE EXTERNAL DATA SOURCE ds_Blob
WITH
(
LOCATION = 'abs://<container>@<conta>.blob.core.windows.net',
CREDENTIAL = cred_Blob
);
GO
-- File format Parquet
CREATE EXTERNAL FILE FORMAT ff_Parquet
WITH (FORMAT_TYPE = PARQUET);
GO
-- Consulta ad hoc, sem criar tabela: OPENROWSET com schema inferido
SELECT TOP (10) *
FROM OPENROWSET
(
BULK 'vendas/2025/*.parquet',
DATA_SOURCE = 'ds_Blob',
FORMAT = 'PARQUET'
) AS v;
-- External table sobre uma pasta inteira de arquivos Parquet
CREATE EXTERNAL TABLE dbo.ext_Vendas
(
VendaId INT,
ClienteId INT,
Valor DECIMAL(10,2),
DataVenda DATE
)
WITH
(
LOCATION = 'vendas/2025/',
DATA_SOURCE = ds_Blob,
FILE_FORMAT = ff_Parquet
);
GO
-- CETAS: exporta o resultado de uma query para Parquet no storage
EXEC sp_configure 'allow polybase export', 1;
RECONFIGURE;
GO
CREATE EXTERNAL TABLE dbo.ext_ResumoUF
WITH
(
LOCATION = 'resumo/uf/',
DATA_SOURCE = ds_Blob,
FILE_FORMAT = ff_Parquet
)
AS
SELECT UF, COUNT(*) AS Qtde
FROM dbo.ext_Cliente
GROUP BY UF;
Pegadinhas
- External tables são somente leitura para INSERT, UPDATE e DELETE. Para escrever no storage use CETAS.
- Não há índices em external tables; para ajudar o otimizador, crie estatísticas.
- Desde o SQL Server 2022, conectividade com Hadoop e scale-out groups do PolyBase foram removidas. Os prefixos atuais são abs://, adls:// e s3:// para arquivos.
- A ordem de criação importa: sem master key não há credential; sem credential o data source falha na primeira consulta.
- O schema da external table é validado na criação para fontes ODBC (sqlserver://, oracle://), mas para arquivos o erro só aparece ao consultar.
Conclusão
External tables mudam a pergunta de “como trago esses dados para o banco?” para “preciso mesmo trazer?”. Para a DP-800, a sequência de objetos e a diferença entre external table, OPENROWSET e CETAS valem ouro. No próximo post vamos para o mundo da confiança verificável com as ledger tables.
Link para os scripts no GitHub
-- Limpeza opcional desta parte
USE DP800_Lab;
DROP EXTERNAL TABLE IF EXISTS dbo.ext_Cliente;
DROP EXTERNAL DATA SOURCE ds_SqlOrigem;
DROP DATABASE SCOPED CREDENTIAL cred_Origem;
USE master;
DROP DATABASE IF EXISTS DP800_Origem;
DROP LOGIN polybase_leitor;
