top of page

Rychlejší způsob načítání souborů ze SharePointu v Power BI

  • Writer: Vojtěch Šíma
    Vojtěch Šíma
  • Dec 30, 2025
  • 7 min read
tl;dr Pokud chceš dosáhnout nejlepšího výkonu pro velké množství souborů, použij SharePoint.Contents s ApiVersion = 15 a dej všechny potřebné soubory do jedné složky.

Rozdíl mezi SharePoint.Files a SharePoint.Contents

SharePoint.Files a SharePoint.Contents jsou dvě vestavěné funkce v Power Query, které slouží k snadnému získání dat ze SharePointu pomocí uživatelsky přívětivého klikání. Tedy alespoň ta první. Pokud se proklikáš nabídkou a vybereš "SharePoint folder" ze seznamu konektorů, automaticky se použije funkce SharePoint.Files.


Možná jsi už slyšel o problémech nebo potenciální pomalosti téhle automatické funkce, takže jsi ručně přepsal "Files" na "Contents" a teď používáš SharePoint.Contents.


Otázka je ale, jestli jsi tím něco vyřešil.


Jednoduché vysvětlení, proč je jeden nebo druhý lepší/rychlejší/silnější, je následující. V říši klikání to funguje tak, že když použiješ Files, vylistuješ veškerý binární obsah z celé SharePoint site a pak si vybereš to, co chceš, pomocí filtrování nebo přímého výběru. V případě Contents máš k dispozici jednoduchou navigaci, která prochází složky; podobně jako v jakémkoli správci souborů. Takže si proste klikáš složky a podsložky.


Proč je to pomalé a kdo je rychlejší?

Obecně by měl být Contents rychlejší, ALE záleží na několika faktorech. Když nebudu mluvit příliš technicky (později to vysvětlím do velkého detailu, neboj), rychlost bude svázána s celkovým počtem souborů na tvém SharePointu a přesnou verzí Contents/Files, kterou použiješ. V tuto chvíli, pokud nezadáš žádnou verzi, Contents poběží na verzi 14. Tato verze se chová podobně jako výchozí chování Files: načte metadata a provede discovery, poté (v případě Contents) naviguje složku po složce nebo podle navigace, kterou sis definoval, načte kontextové informace o souboru a nakonec stáhne obsah souboru.


Tohle je docela neefektivní a Contents s defaultní API verzí může mít dokonce horší výkon než stejný test s Files.


S ApiVersion = 15 dává Contents najednou smysl. Přeskakuje většinu kontrol metadat a discovery fází a načítá obsah po složkách okamžitě, přičemž kopíruje tvou navigaci. A to se vyplatí.


Je to ale rychlejší než Files? No, tady přichází ta část "záleží": čím více souborů na webu máš, tím rychlejší Contents bude, ale ne drasticky. I když Files posílá extra web requesty, rychlost není o tolik horší, pokud se snažíš napodobit stejné chování jako u Contents. Rozdíl by měl být svázán s discovery fází u Files, která je stránkována po tisících, takže jakmile překročíš 1001 souborů, měl bys začít být o něco rychlejší. Také technicky děláš extra request pro každý jednotlivý soubor, takže tyto milisekundy se nasčítají.


Abych to shrnul, použití ApiVersion = 15 a SharePoint.Contents by mělo být rychlejší.

= SharePoint.Contents("https://tenant.sharepoint.com/sites/siteName", [ApiVersion=15])

Existuje také možnost zvolit Implementation, ale při použití ApiVersion=15 a Implementation="2.0" oproti nepoužití této implementace jsem nenašel velký rozdíl.

Výsledky Benchmarku

Společné nastavení testu

  • Načtené soubory: 79 (Identické .xlsx soubory)

  • Velikost souboru: 1.25 MB na soubor

  • Struktura dat: 4 sloupce, 58 605 řádků na soubor

  • Celkový objem: 4 629 716 řádků

  • Přesnost: přibližně ±5 sekund.

Scénář č. 1

Kontext: 7 325 souborů celkem na stránce/site.

Konektor

Možnosti funkce

Čas (mm:ss)

SharePoint.Contents

ApiVersion = 14 (Default)

02:00

SharePoint.Files

ApiVersion = 15 (Default)

01:00

SharePoint.Contents

ApiVersion = 15

00:53

SharePoint.Contents

ApiVersion = 15, Implementation = 2.0

00:52

Scénář č. 1

Kontext: 26 573 souborů celkem na stránce/site

Nastavení je identické jako u Scénáře č. 1, ale s výrazně větším počtem souborů umístěných mimo cílovou složku, avšak stále na stejném webu/stránce.

Konektor

Možnosti funkce

Čas (mm:ss)

SharePoint.Contents

ApiVersion = 14 (Default)

05:03

SharePoint.Files

ApiVersion = 15 (Default)

01:30

SharePoint.Contents

ApiVersion = 15

00:50

SharePoint.Contents

ApiVersion = 15, Implementation = 2.0

00:55

Dlouhá doba načítání při použití ApiVersion = 14 u SharePoint.Contents je primárně způsobena starými OData requesty provádějícími discovery; tyto requesty tak trochu samy sobě brání v rychlejším odesílání.

Z benchmarků můžeš vidět, že s nárůstem počtu souborů musí konektor SharePoint.Files provádět dodatečné discovery, což ho zpomaluje. Naproti tomu SharePoint.Contents (s ApiVersion = 15) je stabilní a čísla jsou identická (v rámci uvedené přesnosti). Proto by při správném použití měl být vítězem SharePoint.Contents.


Detailnější popis korelace s mnžostvím souborů níže

Dodatečná poznámka ke kombinování souborů

Ještě jedna poznámka navíc: ať už použiješ snadnou možnost kombinování souborů klikáním (ta ošklivá vestavěná věc, co vytvoří hromadu extra balastu), nebo si definuješ transformaci pro každý soubor a aplikuješ ji sám, z hlediska rychlosti nebo zpracování se nic moc nemění. Ale samozřejmě, postavit si to sám je čistší a snáze spravovatelné... a taky je za to zlatý bludišťák.


Alternativní rychlý způsob načítání SharePoint souborů

Teď se pojďme podívat, jestli existuje ještě rychlejší způsob. Spoiler: jo, ale jen o trošičku. Možná stáhneš jednu nebo dvě sekundy.


SharePoint sám o sobě není úplně stavěný na hromadné stahování souborů (bulk retrieval) a není to ani úplně to správné úložiště. Microsoft rozhodně nabízí lepší řešení, ale pro tento článek je budu ignorovat. Mohl bych jednoduše říct, že nejrychlejší způsob, jak načíst soubory ze SharePointu, je přesunout je jinam, parsovat je do databáze a data tahat odtamtud, ale to jde tak trochu proti smyslu celého tohoto článku.


okud je tu nějaký čtenář, který rád říká "ehm, ackchyually,", jasně, máš pravdu: buď implementuj inkrementální refresh na SharePoint zdroji, nebo přesuň soubory pryč. Rozhodně existuje lepší způsob než denně ládovat desítky nebo stovky souborů do Power BI.


Když máme tohle z krku, pojďme se podívat na to, jak dostat soubory přímo ze SharePointu co alternativním rychlým způsobem, uvnitř Power Query.


SharePoint.Files vs SharePoint.Contents z technické hlediska

Dříve jsem ti slíbil technické detaily o vnitřním fungování SharePoint.Files a SharePoint.Contents. Abychom pochopili a lépe uchopili nejrychlejší způsob sběru souborů, dovol mi nejdříve představit klíčové koncepty, které potřebujeme k vybudování lepšího řešení.


Pro toto použiji ApiVersion = 15 u obou, aby byly testy fér.


SharePoint.Files

Proces začíná voláním pro získání Document library. To se děje přes sites/Experiments/_api/web/lists/? s filtry pro získání nesystémových dokumentů s více než 'žádným' souborem.


Poté pošle requesty pro metadata a s ID document library začne discovery fázi skrze /RenderListDataAsStream jako POST request. Toto je drahý způsob, jak získávat položky na SharePointu. Je drahý, protože vrací spoustu dat navíc; je to tak trochu myšleno pro vizuální reprezentaci na webu, takže pro joby na pozadí je to příliš heavy.


Sskenuje všechny složky a podsložky a hledá soubory. Tento sken je extrémně divný; defaultně skenuje celou site po 1 000 položkách na stránku. Nicméně, pokud jsou složka a soubory, které chceš, na začátku seznamu, může to skenování zastavit, jakmile je najde. Ale to "může" je ta divná část.


Tady je příklad: Řekněme, že tvá existující složka má ID 7489. Všechny soubory pod ní jsou posloupné, mají inkrement plus jedna, třeba od ID 7490 do 7800. Všechny soubory a jakákoli podsložka v té cestě se vejdou do té konkrétní stránky, takže pak proces "může" přestat skenovat. Avšak pokud nyní přidáš nový soubor do té složky s ID 13000, protože jsi mezitím vytvořil 5 000 souborů jinde, můžeš tento hladký průběh skenování rozbít. Engine nyní musí stránkovat dál skrz všechny soubory na webu/site, aby našel ten poslední soubor. To je teorie, kterou jsem zatím posbíral.


Stále nejsem s tímto chováním či vysvětlením na stopro happy, takže očekávej v budoucnu třeba nějaké upřesnění. Ale v podstatě pro teď si jen pamatuj: každý soubor a složka má unikátní ID, které je vytvářeno sekvenčně. Pokud přidáš nové soubory do starších složek, budeš muset proskenovat celý web, protože se obsah načítá chronologicky, čímž se zvyšuje čas načítání dat.


Jakmile data najdeš, pro každý soubor to pošle api/contextinfo. Tento request je vyžadován kvůli digest renderu z discovery fáze a obsahuje metadata, nicméně je to pár bytů velké, takže žádná hrůza. No a potom všem stáhne obsah souboru pomocí api/web/getfilebyserverrelativeurl(path)/$value, což je vlastní soubor.


SharePoint.Contents

Tohle je mnohem přímočařejší a tvoje hlava u toho nebude dělat 'jauvajs jauvajs'. Proces začíná replikací navigace, kterou sis nakonfiguroval ve svých krocích v Power Query. Podle tvé nagiace tedy pošleš api/Web/GetFolderByServerRelativePath(path)/Folders a api/Web/GetFolderByServerRelativePath(path)/Files z kořenové složky knihovny až do poslední složky, kterou jsi definoval ve svých krocích.


Jakmile je tohle hotové, podobně jako u SharePoint.Files, začne to stahovat samotné soubory pomocí _api/web/getfilebyserverrelativeurl(path)/$value, a to je v podstatě vše.


Vlastní řešení pro získání dat ze SharePointu

Teď, když chápeme, co SharePoint dělá pod pokličkou, můžeme tento proces replikovat, a trochu ho optimalizovat. Zkoumal jsem další potenciální endpointy, abych zjistil, jestli bychom nemohli získat data hromadně efektivněji, ale pro use casy v Power Query jsou možnosti omezené. Dokonce ani Microsoft Graph API nenabízí pro toto specifické sekvenční stahování souborů výraznou rychlostní výhodu a přináší extra security setup.


Technicky existuje /batch endpoint, který ti umožní requesty sdružovat. Avšak parsovat multipart odpovědi pro komplexní binární soubory, jako je třeba Excel, je v M docela složité a nepřináší to dostatečný nárůst výkonu, aby to ospravedlnilo složitost. Také jsem chtěl upřednostnit snadnost použití ohledně autorizace. Řešení níže spoléhá na vestavěnou autentizaci organizačním účtem, kterou už používáš pro SharePoint.Contents, což tě uštědří od stavění vlastního OAuth2 flow.


Strategie je přímočará. Budeme předpokládat, že všechna tvá cílová data leží uvnitř specifické složky a nevyžadují komplexní filtrování. V případě, že to filtrování potřebuješ, můžeš jednoduše expandovat více polí a provést jakékoli úpravy po načtení metadat souboru. Vylistujeme všechny soubory uvnitř cílové složky, abychom získali jejich ServerRelativeUrl. Poté, podobně jako nativní konektory, stáhneme obsah jeden po druhém pomocí GetFileByServerRelativeUrl. Tento přístup minimalizuje počet requestů, protože přeskakujeme iterativní navigaci složku po složce a skáčeme přímo ke zdroji.


let
    // config here
    tenantUrl = "https://tenant.sharepoint.com",
    siteUrlPath = "sites/SiteName",
    targetFolderServerRelativeUrl = "/sites/SiteName/Shared Documents/TargetFolder",

    getListOfFiles = 
    Json.Document(
        Web.Contents(tenantUrl, [
            RelativePath = siteUrlPath & "/_api/web/GetFolderByServerRelativeUrl('" & targetFolderServerRelativeUrl & "')/Files",
            Headers = [Accept="application/json;odata=nometadata"]
            ]
        )
    ),

    extractServerRelativeUrlAndBuffer = List.Transform(getListOfFiles[value], each [ServerRelativeUrl])),

    retrieveContentForFile = (serverRelativeUrl as text) =>
        let 
            binaryContent = Web.Contents(tenantUrl, [
                RelativePath = siteUrlPath & "/_api/web/GetFileByServerRelativeUrl('" & serverRelativeUrl & "')/$value"
                ]
            ),
            // transformations here
            processedData = binaryContent
        in 
            processedData,

    combineAllFiles = Table.Combine(List.Transform(extractServerRelativeUrlAndBuffer, each retrieveContentForFile(_)))
in
    combineAllFiles

Ve zkratce, začneš voláním GetFolderByServerRelativeUrl na tvou cílovou složku. To načte seznam až 5 000 souborů. Ber na vědomí, že pokud máš více souborů, request selže, protože tento konkrétní endpoint nepodporuje stránkování.


Z této odpovědi extrahuješ ServerRelativeUrl pro každý soubor. Poté pro každou položku v seznamu zavoláš osvědčený endpoint GetFileByServerRelativeUrl. Ten vrátí binární data, což ti umožní provést jakékoli nezbytné transformace přímo uvnitř smyčky.


Pokud chceš nejlepší možný výkon, můžeš experimentovat s Binary.Buffer nebo ladit možnosti Excelu jako useHeaders či delayTypes. Můžeš také zkusit transformovat list na tabulku a načítat obsah skrze nový sloupec, což může dosáhnout vyšší concurrency. Nicméně měj na paměti, že toto jsou vysoce experimentální optimalizace a výsledky se mohou lišit. Ale co, alespoň teď znáš manuální alternativu k základnímu konektoru a můžeš znít víc cool před svými kolegy.


Shrnutí

Pro mě osobně bylo psaní tohoto blog postu několikahodinovým bojem s renderovací a stránkovací logikou SharePoint.Files, a to vše při snaze pochopit to "proč" za tím vším. Doufám, že sis užil tuhle destilovanou verzi.


Závěrem,, SharePoint.Contents with ApiVersion 15 je často dostatečující. Avšak pokud plánuješ provádět jakékoli úpravy na základě metadat souborů, toto vlastní řešení může být rychlejší a naučíš se při tom jednu nebo dvě věci.


Rozhodně tento blog sleduj. Stále mám v úmyslu vyřešit výzvu hromadného stahování ze SharePointu, protože musí existovat lepší způsob, i v říši Power Query.


Rychlejší způsob načítání souborů ze SharePointu v Power BI
Rychlejší způsob načítání souborů ze SharePointu v Power BI

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
bottom of page