Sim eu não enlouqueci, na técnica que vamos apresentar que foi criada pelo Dustin Ryan aqui nesse artigo https://sqldusty.com/2020/05/20/power-bi-incremental-refresh-with-web-api-data-source/ e também demonstrada pelo Gilbert da Fourmoo (adoro o símbolo da empresa kakakkaka) aqui nesse outro excelente artigo https://www.fourmoo.com/2020/06/10/how-you-can-incrementally-refresh-any-power-bi-data-source-this-example-is-a-csv-file/ , permite que você faça atualização incremental para qualquer FUCKIN tipo de fonte de dados e isso é sensacional.
MASSSSSSS... eu fui um pouco além e decidi mudar uma coisinha que pode fazer uma ENORME diferença, nos artigos citados acima é utilizada uma fonte do SQL Server (que claro poderia ser um Oracle, ou qualquer fonte que utilize query folding) já que QueryFolding é uma premissa necessária para a utilização da Atualização Incremental, como eu já falei pra vocês nesse vídeo aqui no canal Planilheiros Brasil e aconselho que veja esse vídeo antes de seguir lendo esse artigo.
Bem e se a minha fonte onde é aplicado a atualização incremental for o PRÓPRIO POWER BI?
😱😱😱😱😱😱😱😱
Então vamos lá mostrar como ficou a minha brincadeira com Atualizando qualquer coisa com incremental, ou quase qualquer coisa.
😱😱😱😱😱😱😱😱
Então vamos lá mostrar como ficou a minha brincadeira com Atualizando qualquer coisa com incremental, ou quase qualquer coisa.
Esse artigo é um complemento ao vídeo dessa semana do HappyHourComDados que se você não assistiu ou é doido ou bebe gás.
Como Funciona por trás dos Panos a Atualização Incremental?
Como você já deve saber o Power BI tanto na nuvem quanto no serviço utiliza um modelo de dados que é análogo ao que temos no Analysis Services. Quando ativamos a Atualização Incremental o que ocorre é uma divisão da minha tabela em "mini pedacinhos" onde cada pedaço vai ter uma parte da partição.
Mas o que define como será essa divisão da partição?
A definição da menor unidade de partição é definida pelos parâmetros do periodo que você deseja armazenar seus dados e o período que você deseja atualizar seus dados conforme imagem abaixo.
No exemplo acima na configuração da atualização incremental eu informei que quero que seja mantido sempre o periodo dos últimos 3 meses e que a atualização dos dados ocorra apenas dos últimos 3 dias.
Nesse caso no dia de hoje 12/06/2020 seriam criados 3 particionamentos com dados mensais de Março, Abril e Maio de 2020 e 12 particionamentos com dados diários de 01/06 a 12/06, conforme mostra a nossa consulta ao modelo de dados do Power BI que podemos fazer utilizando o SSMS (como conectar a uma fonte de dados usando XMLA endpoints do Power BI você pode ver AQUI )
Nesse caso no dia de hoje 12/06/2020 seriam criados 3 particionamentos com dados mensais de Março, Abril e Maio de 2020 e 12 particionamentos com dados diários de 01/06 a 12/06, conforme mostra a nossa consulta ao modelo de dados do Power BI que podemos fazer utilizando o SSMS (como conectar a uma fonte de dados usando XMLA endpoints do Power BI você pode ver AQUI )
E essa lógica será aplicada sempre sem que você tenha feito muito esforço.
É possível ver no Modelo também quais os detalhamentos de cada uma das partições se você no SSMS usar o Script de Tabela. Podemos ver aí por exemplo o nome, a granulidade e o range de datas inicial e final.
É possível ver no Modelo também quais os detalhamentos de cada uma das partições se você no SSMS usar o Script de Tabela. Podemos ver aí por exemplo o nome, a granulidade e o range de datas inicial e final.
Então no momento da atualização do meu conjunto de dados o que o Power BI Serviço está fazendo é mandando atualizar apenas as últimas 3 partições que são referentes ao dia de hoje, ontem e antes de ontem. Diariamente uma nova partição é criada referente ao dia atual e na virada de cada mês as partições diárias do mês anterior são unificadas numa única partição. Legal hein?
Esse conceito também abre espaço para que você possa atualizar uma partição específica que tenha sofrido alteração que não deveria, como no caso de uma atualização de um balanço que precisou ser corrigido depois de passado o prazo de encerramento, isso é papo para outro artigo...
Então vamos à atualização incremental
Para testar inicialmente se funcionava a minha POC eu criei uma tabela que continham uma listas de datas usando o seguinte código M que você pode copiar e colar numa nova consulta nula (COLE USANDO O EDITOR AVANÇADO OK?)
Essa função retornará uma lista de DateTime de 01/04/2020 até o dia de hoje.
Criamos então nossos parâmetros de RangeStart e RangeEnd e aplicamos eles à tabela criada anteriormente (novamente você pode ver isso tudo no meu vídeo no canal planilheiros que indiquei acima) e no final teremos isso.
Essa função retornará uma lista de DateTime de 01/04/2020 até o dia de hoje.
Criamos então nossos parâmetros de RangeStart e RangeEnd e aplicamos eles à tabela criada anteriormente (novamente você pode ver isso tudo no meu vídeo no canal planilheiros que indiquei acima) e no final teremos isso.
Vamos então fechar e aplicar esse código configurar para essa tabela "Consulta1" a retenção de dados dos últimos 90 dias e atualização dos últimos 3 dias.
Publicamos esse pequeno rapaz e atualizamos 2 vezes a primeira serve para que seja feita a atualização Full e criação das partições no Modelo e a segunda para que seja feita atualização apenas das partições dos últimos 3 dias... e ...
Notem então que a primeira atualização que iniciou as 1:56:57 demorou 38 segundos, e a segunda atualização demorou apenas 6 segundos. Depois desse processo eu coloquei esse workspace que publiquei em uma capacidade premium para que pudesse validar como ficaram as informações das partições e...
Apenas as partições dos últimos 3 dias foram atualizadas na segunda atualização o que é absolutamente LINDO e prova o conceito que estava buscando UFA...
Chegando nesse processo agora você pode aplicar a qualquer fonte (ou quase) esse mesmo conceito. Se eu tenho por exemplo uma API como essa https://covid19-brazil-api.now.sh/api/report/v1/brazil/20200520 que tem na última parte a DATA no formato "yyyyMMdd" ou até numa Query eu posso criar uma função personalizada onde eu consiga buscar dados de cada dia usando o conceito que criei acima... conforme você pode conferir no código M abaixo.
O Arquivo completo dessa consulta a API você pode baixar AQUI
Nós links que mandei no início desse artigo tem exemplos com arquivos em um blob e também api, você pode então usar a sua criatividade e agora o céu é o limite.
Grande abraço e até a próxima.
Grande abraço e até a próxima.
Essa tive que olhar no SSMS e né que funciona mesmo, vou tentar com outras fontes de dados também!!!!!
ResponderExcluirDuvidou de MIM???? rs.... legal lá da pra ate atualizar uma partição antiga na mão isso é top.
ResponderExcluir@Rafael, Obrigado pelo conteúdo. Mas confesso que estou apanhando para aplicar em uma Consulta no SQL sem Query Folding. Quando der, se possível é claro, posta algum conteúdo fazendo a atualização incremental para query sql sem query folding, por favor.
ExcluirTop Rafael parabéns!
ResponderExcluirGostei da ideia. No meu caso, tenho uma consulta via ODBC na AWS (Athena). Se entendi corretamente, nesse seu método, a função de busca será chamada dia a dia, pois é uma coluna calculada no M. Cada linha chama a função. Correto?
ResponderExcluirNo caso da AWS, nós pagamos por dados lidos. Tenho minhas dúvidas, nesse caso, se sairá mais caro eu fazer 1 consulta de 12 meses corridos ou 365 consultas (na primeira carga, 1 par acada linha).
Excelente explicação. vcs são feras mesmo!!!
ResponderExcluirPorém teve algo que me chamou atenção durante o vídeo que é a questão da atualização automática para API.
Abaixo segue o código que uso para buscar os dados de uma API paginada e que por sinal não atualiza automaticamente.
No caso abaixo o RelativePath deveria ficar em que ponto do código?
o que muda na url desta chamada é o offset
let
request = Json.Document(Web.Contents("https://api.vhsys.com/v2/ordens-servico",
[
Headers=[
#"Access-Token"="XXXXX",
#"Secret-Access-Token"="XXXXX",
#"Cache-Control"="no-cache",
#"Content-type"="application/json"
]
]
)),
paging = request[paging][total],
ListOffset = List.Generate(
() => 0,
each _ < paging,
each _ + 250
),
#"Convertido para Tabela" = Table.FromList(ListOffset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Colunas Renomeadas" = Table.RenameColumns(#"Convertido para Tabela",{{"Column1", "Offset"}}),
#"Função Personalizada Invocada" = Table.AddColumn(#"Colunas Renomeadas", "Source", each Source_OS([Offset])),
#"Source Expandido" = Table.ExpandListColumn(#"Função Personalizada Invocada", "Source"),
#"Source Expandido1" = Table.ExpandRecordColumn(#"Source Expandido", "Source", {"id_ordem", "id_pedido", "id_cliente", "nome_cliente",...},
#"Erros Removidos" = Table.RemoveRowsWithErrors(#"Tipo Alterado", {"data_entrega"}),
#"Linhas Filtradas" = Table.SelectRows(#"Erros Removidos", each [data_cad_pedido] >= RangeStart and [data_cad_pedido] < RangeEnd)
in
#"Linhas Filtradas"
Alexandre pelo que entendi, o RangeStart e o RangeEnd devem estar antes de você utilizar utilizar a "função personalizada Invocada", vai ter que fazer uma coluna de data e hora correspondente a n° da pagina (pagina mais recente = hoje e ir diminuindo a data quanto a pagina mais antiga)
ResponderExcluir