Consultar um armazém de dados
Quando as tabelas de dimensões e fatos em um data warehouse tiverem sido carregadas com dados, você poderá usar SQL para consultar as tabelas e analisar os dados que elas contêm. A sintaxe Transact-SQL usada para consultar tabelas em um pool SQL dedicado Synapse é semelhante ao SQL usado no SQL Server ou no Banco de Dados SQL do Azure.
Agregação de medidas por atributos de dimensão
A maioria das análises de dados com um data warehouse envolve a agregação de medidas numéricas em tabelas de fato por atributos em tabelas de dimensão. Devido à forma como um esquema de estrela ou floco de neve é implementado, as consultas para a execução deste tipo de agregação dependem de cláusulas JOIN para conectar tabelas de fatos a tabelas de dimensão, e de uma combinação de funções agregadas e cláusulas GROUP BY para definir as hierarquias de agregação.
Por exemplo, o SQL a seguir consulta as tabelas FactSales e DimDate em um data warehouse hipotético para agregar valores de vendas por ano e trimestre:
SELECT dates.CalendarYear,
dates.CalendarQuarter,
SUM(sales.SalesAmount) AS TotalSales
FROM dbo.FactSales AS sales
JOIN dbo.DimDate AS dates ON sales.OrderDateKey = dates.DateKey
GROUP BY dates.CalendarYear, dates.CalendarQuarter
ORDER BY dates.CalendarYear, dates.CalendarQuarter;
Os resultados dessa consulta seriam semelhantes à tabela a seguir:
| Ano Calendário | Trimestre do Calendário | Vendas totais |
|---|---|---|
| 2020 | 1 | 25980.16 |
| 2020 | 2 | 27453.87 |
| 2020 | 3 | 28527,15 |
| 2020 | 4 | 31083.45 |
| 2021 | 1 | 34562.96 |
| 2021 | 2 | 36162.27 |
| ... | ... | ... |
Você pode unir quantas tabelas de dimensão forem necessárias para calcular as agregações necessárias. Por exemplo, o código a seguir estende o exemplo anterior para dividir os totais de vendas trimestrais por cidade com base nos detalhes de endereço do cliente na tabela DimCustomer :
SELECT dates.CalendarYear,
dates.CalendarQuarter,
custs.City,
SUM(sales.SalesAmount) AS TotalSales
FROM dbo.FactSales AS sales
JOIN dbo.DimDate AS dates ON sales.OrderDateKey = dates.DateKey
JOIN dbo.DimCustomer AS custs ON sales.CustomerKey = custs.CustomerKey
GROUP BY dates.CalendarYear, dates.CalendarQuarter, custs.City
ORDER BY dates.CalendarYear, dates.CalendarQuarter, custs.City;
Desta vez, os resultados incluem um total trimestral de vendas para cada cidade:
| Ano Calendário | Trimestre do Calendário | Localidade | Vendas totais |
|---|---|---|---|
| 2020 | 1 | Amesterdão | 5982.53 |
| 2020 | 1 | Berlim | 2826.98 |
| 2020 | 1 | Chicago | 5372.72 |
| ... | ... | ... | .. |
| 2020 | 2 | Amesterdão | 7163.93 |
| 2020 | 2 | Berlim | 8191.12 |
| 2020 | 2 | Chicago | 2428.72 |
| ... | ... | ... | .. |
| 2020 | 3 | Amesterdão | 7261.92 |
| 2020 | 3 | Berlim | 4202.65 |
| 2020 | 3 | Chicago | 2287.87 |
| ... | ... | ... | .. |
| 2020 | 4 | Amesterdão | 8262.73 |
| 2020 | 4 | Berlim | 5373.61 |
| 2020 | 4 | Chicago | 7726.23 |
| ... | ... | ... | .. |
| 2021 | 1 | Amesterdão | 7261.28 |
| 2021 | 1 | Berlim | 3648.28 |
| 2021 | 1 | Chicago | 1027.27 |
| ... | ... | ... | .. |
Junta-se em um esquema de flocos de neve
Ao usar um esquema de flocos de neve, as dimensões podem ser parcialmente normalizadas; exigindo várias junções para relacionar tabelas de fatos com dimensões de flocos de neve. Por exemplo, suponha que seu data warehouse inclua uma tabela de dimensões DimProduct a partir da qual as categorias de produtos foram normalizadas em uma tabela DimCategory separada. Uma consulta para agregar itens vendidos por categoria de produto pode ser semelhante ao exemplo a seguir:
SELECT cat.ProductCategory,
SUM(sales.OrderQuantity) AS ItemsSold
FROM dbo.FactSales AS sales
JOIN dbo.DimProduct AS prod ON sales.ProductKey = prod.ProductKey
JOIN dbo.DimCategory AS cat ON prod.CategoryKey = cat.CategoryKey
GROUP BY cat.ProductCategory
ORDER BY cat.ProductCategory;
Os resultados desta consulta incluem o número de itens vendidos para cada categoria de produto:
| Categoria de Produto | ItensVendidos |
|---|---|
| Acessórios | 28271 |
| Bits e pedaços | 5368 |
| ... | ... |
Observação
As cláusulas JOIN para FactSales e DimProduct e para DimProduct e DimCategory são necessárias, mesmo que nenhum campo de DimProduct seja retornado pela consulta.
Usando funções de classificação
Outro tipo comum de consulta analítica é particionar os resultados com base em um atributo de dimensão e classificar os resultados dentro de cada partição. Por exemplo, você pode querer classificar as lojas a cada ano pela receita de vendas. Para atingir esse objetivo, você pode usar Transact-SQL funções de classificação , como ROW_NUMBER, RANK, DENSE_RANKe NTILE. Essas funções permitem que você particione os dados em categorias, cada uma retornando um valor específico que indica a posição relativa de cada linha dentro da partição:
- ROW_NUMBER retorna a posição ordinal da linha dentro da partição. Por exemplo, a primeira linha é numerada como 1, a segunda 2 e assim por diante.
- RANK retorna a posição classificada de cada linha nos resultados ordenados. Por exemplo, em uma partição de lojas ordenadas por volume de vendas, a loja com o maior volume de vendas é classificada como 1. Se várias lojas tiverem os mesmos volumes de vendas, elas serão classificadas da mesma forma, e a classificação atribuída às lojas subsequentes reflete o número de lojas que têm volumes de vendas mais altos - incluindo empates.
- DENSE_RANK classifica linhas em uma partição da mesma forma que RANK, mas quando várias linhas têm a mesma classificação, as linhas subsequentes são posições de classificação ignoram empates.
-
NTILE retorna o percentil especificado no qual a linha cai. Por exemplo, em uma partição de lojas ordenadas por volume de vendas,
NTILE(4)retorna o quartil em que o volume de vendas de uma loja o coloca.
Por exemplo, considere a consulta seguinte:
SELECT ProductCategory,
ProductName,
ListPrice,
ROW_NUMBER() OVER
(PARTITION BY ProductCategory ORDER BY ListPrice DESC) AS RowNumber,
RANK() OVER
(PARTITION BY ProductCategory ORDER BY ListPrice DESC) AS Rank,
DENSE_RANK() OVER
(PARTITION BY ProductCategory ORDER BY ListPrice DESC) AS DenseRank,
NTILE(4) OVER
(PARTITION BY ProductCategory ORDER BY ListPrice DESC) AS Quartile
FROM dbo.DimProduct
ORDER BY ProductCategory;
A consulta divide os produtos em agrupamentos com base em suas categorias e, dentro de cada partição de categoria, a posição relativa de cada produto é determinada com base em seu preço de tabela. Os resultados dessa consulta podem ser semelhantes à tabela a seguir:
| Categoria de Produto | Nome do Produto | ListPrice | Número da linha | Classificação | DenseRank | Quartil |
|---|---|---|---|---|---|---|
| Acessórios | Widget | 8.99 | 1 | 1 | 1 | 1 |
| Acessórios | Knicknak | 8.49 | 2 | 2 | 2 | 1 |
| Acessórios | Roda dentada | 5,99 | 3 | 3 | 3 | 2 |
| Acessórios | Doodah | 5,99 | 4 | 3 | 3 | 2 |
| Acessórios | Emaranhado | 2.99 | 5 | 5 | 4 | 3 |
| Acessórios | Badabing | 0.25 | 6 | 6 | 5 | 4 |
| Bits e pedaços | Flimflam | 7.49 | 1 | 1 | 1 | 1 |
| Bits e pedaços | Snickity wotsit | 6.99 | 2 | 2 | 2 | 1 |
| Bits e pedaços | Flange | 4,25 | 3 | 3 | 3 | 2 |
| ... | ... | ... | ... | ... | ... | ... |
Observação
Os resultados da amostra demonstram a diferença entre RANK e DENSE_RANK. Note-se que na categoria Acessórios , os produtos Sprocket e Doodah têm o mesmo preço de tabela; e ambos são classificados como o 3º produto mais caro. O próximo produto mais caro tem um RANK de 5 (há quatro produtos mais caros do que ele) e um DENSE_RANK de 4 (há três preços mais altos).
Para saber mais sobre funções de classificação, consulte Funções de classificação (Transact-SQL) na documentação do Azure Synapse Analytics.
Recuperando uma contagem aproximada
Embora o objetivo de um armazém de dados seja principalmente dar suporte a modelos de dados analíticos e relatórios para a empresa; Analistas de dados e cientistas de dados geralmente precisam realizar alguma exploração inicial de dados, apenas para determinar a escala básica e a distribuição dos dados.
Por exemplo, a consulta a seguir usa a COUNT função para recuperar o número de vendas para cada ano em um data warehouse hipotético:
SELECT dates.CalendarYear AS CalendarYear,
COUNT(DISTINCT sales.OrderNumber) AS Orders
FROM FactSales AS sales
JOIN DimDate AS dates ON sales.OrderDateKey = dates.DateKey
GROUP BY dates.CalendarYear
ORDER BY CalendarYear;
Os resultados dessa consulta podem ser semelhantes à tabela a seguir:
| Ano Calendário | Encomendas |
|---|---|
| 2019 | 239870 |
| 2020 | 284741 |
| 2021 | 309272 |
| ... | ... |
O volume de dados em um data warehouse pode significar que até mesmo consultas simples para contar o número de registros que atendem aos critérios especificados podem levar um tempo considerável para serem executadas. Em muitos casos, uma contagem precisa não é necessária - uma estimativa aproximada será suficiente. Nesses casos, você pode usar a APPROX_COUNT_DISTINCT função como mostrado no exemplo a seguir:
SELECT dates.CalendarYear AS CalendarYear,
APPROX_COUNT_DISTINCT(sales.OrderNumber) AS ApproxOrders
FROM FactSales AS sales
JOIN DimDate AS dates ON sales.OrderDateKey = dates.DateKey
GROUP BY dates.CalendarYear
ORDER BY CalendarYear;
A APPROX_COUNT_DISTINCT função usa um algoritmo HyperLogLog para recuperar uma contagem aproximada. É garantido que o resultado tenha uma taxa de erro máxima de 2% com 97% de probabilidade, de modo que os resultados desta consulta com os mesmos dados hipotéticos de antes podem ser semelhantes à tabela a seguir:
| Ano Calendário | Aprox. Encomendas |
|---|---|
| 2019 | 235552 |
| 2020 | 290436 |
| 2021 | 304633 |
| ... | ... |
As contagens são menos precisas, mas ainda assim suficientes para uma comparação aproximada das vendas anuais. Com um grande volume de dados, a consulta usando a função é concluída mais rapidamente, e a precisão reduzida pode ser uma compensação aceitável durante a APPROX_COUNT_DISTINCT exploração de dados básicos.
Observação
Consulte a documentação da função APPROX_COUNT_DISTINCT para obter mais detalhes.