Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Hinweis
Datenschutzstufen sind derzeit in Power Platform-Datenflüssen nicht verfügbar, aber das Produktteam arbeitet daran, diese Funktionalität zu aktivieren.
Wenn Sie Power Query für eine beliebige Zeit verwendet haben, haben Sie es wahrscheinlich erlebt. Plötzlich erhalten Sie eine Fehlermeldung, die sich weder durch noch so viel Recherche, Optimieren der Abfrage noch durch energisches Tastaturhämmern beheben lässt, während Sie gerade dabei sind, die Abfrage durchzuführen. Ein Fehler wie:
Formula.Firewall: Query 'Query1' (step 'Source') references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.
Oder vielleicht:
Formula.Firewall: Query 'Query1' (step 'Source') is accessing data sources that have privacy levels which cannot be used together. Please rebuild this data combination.
Diese Formula.Firewall Fehler sind das Ergebnis der Datenschutzfirewall von Power Query (auch bekannt als Firewall), die manchmal den Anschein erweckt, als existiere sie nur, um weltweit Frust bei Datenanalysten zu erzeugen. Glauben Sie es, oder nicht, aber die Firewall dient einem wichtigen Zweck. In diesem Artikel nehmen wir es genauer unter die Lupe, um besser zu verstehen, wie es funktioniert. Mit größerem Verständnis werden Sie hoffentlich in der Lage sein, Firewallfehler in Zukunft besser zu diagnostizieren und zu beheben.
Was ist das?
Der Zweck der Datenschutzfirewall ist einfach: Es ist vorhanden, um zu verhindern, dass Power Query unbeabsichtigt Daten zwischen Quellen ausleckt.
Warum wird dies benötigt? Ich meine, Sie könnten sicherlich einige M erstellen, die einen SQL-Wert an einen OData-Feed übergeben würden. Das wäre jedoch ein beabsichtigtes Datenleck. Der Mashup-Autor würde (oder zumindest sollte) wissen, dass er dies getan hat. Warum ist dann der Schutz vor unbeabsichtigten Datenlecks erforderlich?
Die Antwort? Falten
Falten?
Folding ist ein Begriff, der das Konvertieren von Ausdrücken in M (z. B. Filter, Umbenennungen, Verknüpfungen usw.) in Operationen auf einer Rohdatenquelle (z. B. SQL, OData usw.) beschreibt. Ein großer Teil der Leistungsfähigkeit von Power Query kommt aus der Tatsache, dass Power Query die Vorgänge, die ein Benutzer über seine Benutzeroberfläche ausführt, in komplexe SQL- oder andere Back-End-Datenquellensprachen konvertieren kann, ohne dass der Benutzer diese Sprachen kennen muss. Benutzer profitieren von systemeigenen Datenquellenvorgängen mit einfacher Verwendung einer Benutzeroberfläche, auf der alle Datenquellen mithilfe einer gemeinsamen Gruppe von Befehlen transformiert werden können.
Im Rahmen der Faltung kann Power Query manchmal feststellen, dass die effizienteste Methode zum Ausführen eines bestimmten Mashups darin besteht, Daten aus einer Quelle zu übernehmen und an eine andere zu übergeben. Wenn Sie z. B. eine kleine CSV-Datei mit einer riesigen SQL-Tabelle verknüpfen, möchten Sie wahrscheinlich nicht, dass Power Query die CSV-Datei lesen, die gesamte SQL-Tabelle lesen und diese dann auf Ihrem lokalen Computer zusammenfügen. Sie möchten wahrscheinlich, dass Power Query die CSV-Daten in eine SQL-Anweisung eingliedert und die SQL-Datenbank auffordern, die Verknüpfung auszuführen.
Dies ist, wie unbeabsichtigte Datenlecks auftreten können.
Stellen Sie sich vor, Wenn Sie SQL-Daten hinzugefügt haben, die Mitarbeiter-Sozialversicherungsnummern mit den Ergebnissen eines externen OData-Feeds enthalten, und Sie haben plötzlich festgestellt, dass die Sozialversicherungsnummern von SQL an den OData-Dienst gesendet wurden. Schlechte Nachrichten, richtig?
Dies ist die Art von Szenario, das die Firewall verhindern soll.
Wie funktioniert es?
Die Firewall ist vorhanden, um zu verhindern, dass Daten aus einer Quelle unbeabsichtigt an eine andere Quelle gesendet werden. Einfach genug.
Wie kann diese Mission also erreicht werden?
Dazu teilen Sie Ihre M-Abfragen in sogenannte Partitionen und erzwingen dann die folgende Regel:
- Eine Partition kann entweder auf kompatible Datenquellen zugreifen oder auf andere Partitionen verweisen, aber nicht auf beide.
Einfach... aber verwirrend. Was ist eine Partition? Was macht zwei Datenquellen "kompatibel"? Und warum sollte die Firewall wichtig sein, wenn eine Partition auf eine Datenquelle zugreifen und auf eine Partition verweisen möchte?
Lassen Sie uns dies aufschlüsseln und die vorherige Regel einzeln betrachten.
Was ist eine Partition?
Auf der einfachsten Ebene ist eine Partition nur eine Sammlung einer oder mehrerer Abfrageschritte. Die präziseste Partition (zumindest in der aktuellen Implementierung) ist ein einzelner Schritt. Die größten Partitionen können manchmal mehrere Abfragen umfassen. (Mehr dazu später.)
Wenn Sie mit den Schritten nicht vertraut sind, können Sie sie rechts im Power Query-Editor-Fenster anzeigen, nachdem Sie eine Abfrage ausgewählt haben, im Bereich "Angewendete Schritte ". Die Schritte verfolgen alles, was Sie tun, um Ihre Daten in ihre endgültige Form zu verwandeln.
Partitionen, die auf andere Partitionen verweisen
Wenn eine Abfrage mit der Firewall ausgewertet wird, teilt die Firewall die Abfrage und alle zugehörigen Abhängigkeiten in Partitionen (d. a. Gruppen von Schritten). Wenn eine Partition auf etwas in einer anderen Partition verweist, ersetzt die Firewall den Verweis durch einen Aufruf einer speziellen Funktion namens Value.Firewall. Mit anderen Worten, die Firewall erlaubt nicht, dass Partitionen direkt auf einander zugreifen können. Alle Verweise werden so geändert, dass sie über die Firewall geleitet werden. Stellen Sie sich die Firewall als Gatekeeper vor. Eine Partition, die auf eine andere Partition verweist, muss die Erlaubnis der Firewall einholen, und die Firewall steuert, ob die referenzierten Daten in die Partition zugelassen werden.
Das alles mag ziemlich abstrakt erscheinen, also sehen wir uns ein Beispiel an.
Angenommen, Sie haben eine Abfrage namens "Employees", die einige Daten aus einer SQL-Datenbank abruft. Angenommen, Sie haben auch eine andere Abfrage (EmployeesReference), die einfach auf Mitarbeiter verweist.
shared Employees = let
Source = Sql.Database(…),
EmployeesTable = …
in
EmployeesTable;
shared EmployeesReference = let
Source = Employees
in
Source;
Diese Abfragen enden in zwei Partitionen unterteilt: eine für die Employees-Abfrage und eine für die EmployeesReference-Abfrage (die auf die Employees-Partition verweist). Bei der Auswertung mit der Firewall werden diese Abfragen wie folgt umgeschrieben:
shared Employees = let
Source = Sql.Database(…),
EmployeesTable = …
in
EmployeesTable;
shared EmployeesReference = let
Source = Value.Firewall("Section1/Employees")
in
Source;
Beachten Sie, dass der einfache Verweis auf die Employees-Abfrage durch einen Aufruf Value.Firewallersetzt wird, der den vollständigen Namen der Employees-Abfrage bereitstellt.
Wenn EmployeesReference ausgewertet wird, fängt die Firewall den Aufruf Value.Firewall("Section1/Employees")ab, der nun die Möglichkeit hat, zu steuern, ob (und wie) die angeforderten Daten in die EmployeesReference-Partition fließen. Sie kann eine beliebige Anzahl von Dingen ausführen: Die Anforderung verweigern, die angeforderten Daten puffern (wodurch verhindert wird, dass eine weitere Faltung zur ursprünglichen Datenquelle erfolgt) usw.
So verwaltet die Firewall die Kontrolle über den Datenfluss zwischen Partitionen.
Partitionen, die direkt auf Datenquellen zugreifen
Angenommen, Sie definieren eine Abfrageabfrage1 mit einem Schritt (beachten Sie, dass diese einzelstufige Abfrage einer Firewallpartition entspricht), und dass dieser einzelne Schritt auf zwei Datenquellen zugreift: eine SQL-Datenbanktabelle und eine CSV-Datei. Wie geht die Firewall damit um, da kein Partitionsverweis vorhanden ist und daher kein Aufruf zu Value.Firewall, um es abzufangen? Sehen wir uns die oben erwähnte Regel an:
- Eine Partition kann entweder auf kompatible Datenquellen zugreifen oder auf andere Partitionen verweisen, aber nicht auf beide.
Damit Ihre Abfrage mit einer partitionsbasierten, aber zwei Datenquellen ausgeführt werden kann, müssen die beiden Datenquellen "kompatibel" sein. Mit anderen Worten, es muss in Ordnung sein, dass Daten bidirektional zwischen ihnen geteilt werden. Dies bedeutet, dass die Datenschutzebenen beider Quellen öffentlich sein müssen oder beide organisationsintern sein müssen, da es sich hierbei um die einzigen beiden Kombinationen handelt, die die Freigabe in beide Richtungen ermöglichen. Wenn beide Quellen als "Privat" gekennzeichnet sind, oder eine als "Öffentlich" und eine als "Organisatorisch" gekennzeichnet ist, oder mit einer beliebigen anderen Kombination von Privacy-Levels gekennzeichnet sind, ist das bidirektionale Teilen nicht zulässig. Es ist nicht sicher, dass beide in derselben Partition ausgewertet werden. Dies würde bedeuten, dass unsichere Datenlecks auftreten könnten (aufgrund der Faltung), und die Firewall hätte keine Möglichkeit, sie zu verhindern.
Was geschieht, wenn Sie versuchen, auf inkompatible Datenquellen in derselben Partition zuzugreifen?
Formula.Firewall: Query 'Query1' (step 'Source') is accessing data sources that have privacy levels which cannot be used together. Please rebuild this data combination.
Hoffentlich verstehen Sie jetzt eine der fehlermeldungen, die am Anfang dieses Artikels aufgeführt sind.
Diese Kompatibilitätsanforderung gilt nur innerhalb einer bestimmten Partition. Wenn eine Partition auf andere Partitionen verweist, müssen die Datenquellen aus den referenzierten Partitionen nicht miteinander kompatibel sein. Dies liegt daran, dass die Firewall die Daten puffern kann, wodurch eine weitere Faltung gegen die ursprüngliche Datenquelle verhindert wird. Die Daten werden in den Speicher geladen und behandelt, als ob sie aus dem Nichts stammte.
Warum nicht beides?
Angenommen, Sie definieren eine Abfrage mit einem Schritt (die wiederum einer Partition entspricht), die auf zwei andere Abfragen zugreift (d. a. zwei andere Partitionen). Was wäre, wenn Sie im selben Schritt auch direkt auf eine SQL-Datenbank zugreifen möchten? Warum kann keine Partition auf andere Partitionen verweisen und direkt auf kompatible Datenquellen zugreifen?
Wie Sie bereits gesehen haben, fungiert die Firewall, wenn eine Partition auf eine andere Partition verweist, als Gatekeeper für alle Daten, die in die Partition fließen. Dafür muss es in der Lage sein, zu steuern, welche Daten zugelassen werden. Wenn innerhalb der Partition auf Datenquellen zugegriffen wird und Daten aus anderen Partitionen einfließen, verliert sie ihre Fähigkeit, als Gatekeeper zu agieren, da die einfließenden Daten unbemerkt an eine der intern zugänglichen Datenquellen durchgesickert sein könnten. So verhindert die Firewall, dass eine Partition, die auf andere Partitionen zugreift, direkt auf Datenquellen zugreifen darf.
Was geschieht also, wenn eine Partition versucht, auf andere Partitionen zu verweisen und auch direkt auf Datenquellen zuzugreifen?
Formula.Firewall: Query 'Query1' (step 'Source') references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.
Nun sollten Sie die andere Fehlermeldung, die am Anfang dieses Artikels aufgeführt ist, besser verstehen.
Partitionen im Detail
Wie Sie wahrscheinlich von den vorherigen Informationen erraten können, ist es unglaublich wichtig, wie Abfragen partitioniert werden. Wenn Sie einige Schritte haben, die auf andere Abfragen verweisen, und andere Schritte, die auf Datenquellen zugreifen, erkennen Sie nun hoffentlich, dass das Zeichnen der Partitionsgrenzen an bestimmten Stellen Firewallfehler verursacht, während das Zeichnen an anderen Stellen ermöglicht, dass Ihre Abfrage einwandfrei ausgeführt wird.
Wie genau werden Abfragen partitioniert?
Dieser Abschnitt ist wahrscheinlich das Wichtigste, um zu verstehen, warum Firewallfehler angezeigt werden und wie Sie sie beheben können (sofern möglich).
Hier ist eine allgemeine Zusammenfassung der Partitionierungslogik.
- Anfängliche Partitionierung
- Erstellt eine Partition für jeden Schritt in jeder Abfrage.
- Statische Phase
- Diese Phase hängt nicht von den Auswertungsergebnissen ab. Stattdessen basiert sie darauf, wie die Abfragen strukturiert sind.
- Parameterkürzung
- Kürzt parameterähnliche Partitionen, das heißt, jede, die:
- Verweist nicht auf andere Partitionen
- Enthält keine Funktionsaufrufe
- Ist nicht zyklisch (d. h., es bezieht sich nicht auf sich selbst)
- Beachten Sie, dass das "Entfernen" einer Partition diese effektiv in alle anderen Partitionen einschließt, auf die verwiesen wird.
- Durch das Kürzen von Parameterpartitionen können Parameterverweise, die in Datenquellenfunktionsaufrufen (z. B.
Web.Contents(myUrl)) verwendet werden, funktionieren, anstatt den Fehler "Partition kann nicht auf Datenquellen und andere Schritte verweisen" auszuwerfen.
- Kürzt parameterähnliche Partitionen, das heißt, jede, die:
- Gruppieren (statisch)
- Partitionen werden in der Bottom-up-Abhängigkeitsreihenfolge zusammengeführt. In den resultierenden zusammengeführten Partitionen sind die folgenden getrennt:
- Partitionen in verschiedenen Abfragen
- Partitionen, die nicht auf andere Partitionen verweisen (und somit auf eine Datenquelle zugreifen dürfen)
- Partitionen, die auf andere Partitionen verweisen (und daher nicht auf eine Datenquelle zugreifen dürfen)
- Partitionen werden in der Bottom-up-Abhängigkeitsreihenfolge zusammengeführt. In den resultierenden zusammengeführten Partitionen sind die folgenden getrennt:
- Parameterkürzung
- Diese Phase hängt nicht von den Auswertungsergebnissen ab. Stattdessen basiert sie darauf, wie die Abfragen strukturiert sind.
- Dynamische Phase
- Diese Phase hängt von den Auswertungsergebnissen ab, einschließlich Informationen zu Datenquellen, auf die von verschiedenen Partitionen zugegriffen wird.
- Zuschnitt
- Kürzet Partitionen, die alle folgenden Anforderungen erfüllen:
- Greift nicht auf Datenquellen zu
- Verweist nicht auf Partitionen, die auf Datenquellen zugreifen
- Ist nicht zyklisch
- Kürzet Partitionen, die alle folgenden Anforderungen erfüllen:
- Gruppieren (dynamisch)
- Da nun unnötige Partitionen gekürzt werden, versuchen Sie, Quellpartitionen zu erstellen, die so groß wie möglich sind. Diese Erstellung erfolgt durch Zusammenführen der Partitionen mit den gleichen Regeln, die in der vorherigen statischen Gruppierungsphase beschrieben sind.
Was bedeutet das alles?
Sehen wir uns ein Beispiel an, um zu veranschaulichen, wie die zuvor angelegte komplexe Logik funktioniert.
Hier ist ein Beispielszenario. Dies ist eine recht einfache Zusammenführung einer Textdatei (Kontakte) mit einer SQL-Datenbank (Employees), wobei der SQL Server ein Parameter (DbServer) ist.
Die drei Abfragen
Dies ist der M-Code für die drei in diesem Beispiel verwendeten Abfragen.
shared DbServer = "MySqlServer" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true];
shared Contacts = let
Source = Csv.Document(File.Contents(
"C:\contacts.txt"),[Delimiter=" ", Columns=15, Encoding=1252, QuoteStyle=QuoteStyle.None]
),
#"Promoted Headers" = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),
#"Changed Type" = Table.TransformColumnTypes(
#"Promoted Headers",
{
{"ContactID", Int64.Type},
{"NameStyle", type logical},
{"Title", type text},
{"FirstName", type text},
{"MiddleName", type text},
{"LastName", type text},
{"Suffix", type text},
{"EmailAddress", type text},
{"EmailPromotion", Int64.Type},
{"Phone", type text},
{"PasswordHash", type text},
{"PasswordSalt", type text},
{"AdditionalContactInfo", type text},
{"rowguid", type text},
{"ModifiedDate", type datetime}
}
)
in
#"Changed Type";
shared Employees = let
Source = Sql.Databases(DbServer),
AdventureWorks = Source{[Name="AdventureWorks"]}[Data],
HumanResources_Employee = AdventureWorks{[Schema="HumanResources",Item="Employee"]}[Data],
#"Removed Columns" = Table.RemoveColumns(
HumanResources_Employee,
{
"HumanResources.Employee(EmployeeID)",
"HumanResources.Employee(ManagerID)",
"HumanResources.EmployeeAddress",
"HumanResources.EmployeeDepartmentHistory",
"HumanResources.EmployeePayHistory",
"HumanResources.JobCandidate",
"Person.Contact",
"Purchasing.PurchaseOrderHeader",
"Sales.SalesPerson"
}
),
#"Merged Queries" = Table.NestedJoin(
#"Removed Columns",
{"ContactID"},
Contacts,
{"ContactID"},
"Contacts",
JoinKind.LeftOuter
),
#"Expanded Contacts" = Table.ExpandTableColumn(
#"Merged Queries",
"Contacts",
{"EmailAddress"},
{"EmailAddress"}
)
in
#"Expanded Contacts";
Hier sehen Sie eine Ansicht auf höherer Ebene mit den Abhängigkeiten.
Lassen Sie uns partitionieren
Lassen Sie uns etwas zoomen und Schritte in das Bild einfügen und mit dem Durchlaufen der Partitionierungslogik beginnen. Hier sehen Sie ein Diagramm der drei Abfragen mit den anfänglichen Firewallpartitionen in Grün. Beachten Sie, dass jeder Schritt in einer eigenen Partition beginnt.
Als Nächstes kürzen wir Parameterpartitionen. Daher wird DbServer implizit in die Quellpartition eingeschlossen.
Jetzt führen wir die statische Gruppierung aus. Diese Gruppierung behält die Trennung zwischen Partitionen in separaten Abfragen bei (beachten Sie beispielsweise, dass die letzten beiden Schritte von Mitarbeitern nicht mit den Schritten von Kontakten gruppiert werden) und zwischen Partitionen, die auf andere Partitionen verweisen (z. B. die letzten beiden Schritte von Mitarbeitern) und diejenigen, die nicht (z. B. die ersten drei Schritte von Mitarbeitern) verweisen.
Jetzt betreten wir die dynamische Phase. In dieser Phase werden die oben genannten statischen Partitionen ausgewertet. Partitionen, die nicht auf Datenquellen zugreifen, werden gekürzt. Partitionen werden dann gruppiert, um Quellpartitionen zu erstellen, die so groß wie möglich sind. In diesem Beispielszenario greifen jedoch alle verbleibenden Partitionen auf Datenquellen zu, und es gibt keine weitere Gruppierung, die durchgeführt werden kann. Die Partitionen in unserem Beispiel ändern sich daher in dieser Phase nicht.
Lassen Sie uns vorgeben
Zur Veranschaulichung sehen wir uns jedoch an, was passieren würde, wenn die Kontaktabfrage nicht aus einer Textdatei stammt, sondern in M hartcodiert wäre (vielleicht über das Dialogfeld " Daten eingeben ").
In diesem Fall hat die Kontaktabfrage keinen Zugriff auf Datenquellen. So würde es während des ersten Teils der dynamischen Phase gekürzt werden.
Nachdem die Kontaktepartition entfernt wurde, würden die letzten beiden Schritte von Employees keine Partitionen mehr referenzieren, außer diejenige, die die ersten drei Schritte von Employees enthält. Daher würden die beiden Partitionen gruppiert.
Die resultierende Partition würde wie folgt aussehen.
Beispiel: Übergeben von Daten aus einer Datenquelle an eine andere
Okay, genug abstrakte Erklärung. Sehen wir uns ein gängiges Szenario an, in dem Sie wahrscheinlich auf einen Firewallfehler stoßen und die Schritte zu seiner Behebung kennenlernen.
Stellen Sie sich vor, Sie möchten einen Firmennamen aus dem Northwind OData-Dienst nachschlagen und dann den Firmennamen verwenden, um eine Bing-Suche durchzuführen.
Zuerst erstellen Sie eine Unternehmensabfrage , um den Firmennamen abzurufen.
let
Source = OData.Feed(
"https://services.odata.org/V4/Northwind/Northwind.svc/",
null,
[Implementation="2.0"]
),
Customers_table = Source{[Name="Customers",Signature="table"]}[Data],
CHOPS = Customers_table{[CustomerID="CHOPS"]}[CompanyName]
in
CHOPS
Als Nächstes erstellen Sie eine Suchabfrage , die auf "Unternehmen " verweist und sie an Bing übergibt.
let
Source = Text.FromBinary(Web.Contents("https://www.bing.com/search?q=" & Company))
in
Source
An diesem Punkt treten Probleme auf. Die Auswertung der Suche erzeugt einen Firewallfehler.
Formula.Firewall: Query 'Search' (step 'Source') references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.
Dieser Fehler tritt auf, da der Quellschritt der Suche auf eine Datenquelle (bing.com) verweist und auch auf eine andere Abfrage/Partition (Unternehmen) verweist. Es verstößt gegen die zuvor erwähnte Regel ("eine Partition kann entweder auf kompatible Datenquellen zugreifen oder auf andere Partitionen verweisen, aber nicht beides").
Vorgehensweise Eine Option besteht darin, die Firewall vollständig zu deaktivieren (über die Option "Datenschutz" mit der Bezeichnung "Datenschutzstufen ignorieren" und die Leistung potenziell verbessern). Was ist, wenn Sie die Firewall eingeschaltet lassen möchten?
Um den Fehler zu beheben, ohne die Firewall zu deaktivieren, können Sie "Firma" und "Suche" in einer einzigen Abfrage kombinieren, wie hier:
let
Source = OData.Feed(
"https://services.odata.org/V4/Northwind/Northwind.svc/",
null,
[Implementation="2.0"]
),
Customers_table = Source{[Name="Customers",Signature="table"]}[Data],
CHOPS = Customers_table{[CustomerID="CHOPS"]}[CompanyName],
Search = Text.FromBinary(Web.Contents("https://www.bing.com/search?q=" & CHOPS))
in
Search
Alles geschieht jetzt in einer einzigen Partition. Vorausgesetzt, die Datenschutzstufen für die beiden Datenquellen sind kompatibel, sollte die Firewall jetzt glücklich sein, und Sie erhalten keine Fehlermeldung mehr.
Das war's
Obwohl es viel mehr gibt, die zu diesem Thema gesagt werden könnten, ist dieser Einführungsartikel bereits lang genug. Hoffentlich erhalten Sie ein besseres Verständnis der Firewall und helfen Ihnen, Firewallfehler zu verstehen und zu beheben, wenn sie in Zukunft auftreten.