瞭解 Direct Lake 語意模型的記憶體
本文介紹 Direct Lake 記憶體概念。 它描述 Delta 數據表和 Parquet 檔案。 它也描述如何優化 Direct Lake 語意模型的 Delta 數據表,以及如何維護它們,以協助提供可靠、快速的查詢效能。
差異資料表
OneLake 中有差異數據表。 它們會將檔案型數據組織成數據列和數據行,並可供Microsoft網狀架構計算引擎,例如筆記本、Kusto 和 Lakehouse 和倉儲。 您可以使用數據分析表示式 (DAX)、多維度表達式 (MDX)、T-SQL (Transact-SQL)、Spark SQL,甚至是 Python 來查詢差異數據表。
注意
Delta — 或 Delta Lake — 是開放原始碼記憶體格式。 這表示 Fabric 也可以查詢其他工具和廠商所建立的 Delta 數據表。
Delta 數據表會將其數據儲存在 Parquet 檔案中,通常儲存在 Direct Lake 語意模型用來載入數據的 Lakehouse 中。 不過,Parquet 檔案也可以儲存在外部。 您可以使用 OneLake 快捷方式來參考外部 Parquet 檔案,其指向特定儲存位置,例如 Azure Data Lake Storage (ADLS) Gen2、Amazon S3 記憶體帳戶或 Dataverse。 在幾乎所有情況下,計算引擎會藉由查詢 Delta 數據表來存取 Parquet 檔案。 不過,通常 Direct Lake 語意模型會使用稱為 轉碼的程式,直接從 OneLake 中優化 Parquet 檔案載入數據行數據。
數據版本控制
差異數據表包含一或多個 Parquet 檔案。 這些檔案隨附一組 JSON 鏈接檔案,可追蹤每個與 Delta 數據表相關聯之 Parquet 檔案的順序和本質。
請務必瞭解基礎 Parquet 檔案本質上是累加式的。 因此,將 Delta 命名為累加式數據修改的參考。 每次對 Delta 資料表進行寫入作業時,例如插入、更新或刪除數據時,就會建立新的 Parquet 檔案,以表示數據修改為 版本。 因此 ,Parquet 檔案是不可變的,這表示永遠不會修改它們。 因此,在 Delta 資料表的一組 Parquet 檔案中,數據可能會重複多次。 Delta 架構依賴連結檔案來判斷產生正確查詢結果所需的實體 Parquet 檔案。
請考慮本文用來說明不同數據修改作業之 Delta 數據表的簡單範例。 數據表有兩個數據行,並儲存三個數據列。
ProductID | StockOnHand |
---|---|
A | 1 |
B | 2 |
C | 3 |
Delta 數據表數據會儲存在包含所有數據的單一 Parquet 檔案中,而且有一個單一鏈接檔案,其中包含插入數據時的相關元數據(附加)。
- Parquet 檔案 1:
- ProductID:A、B、C
- StockOnHand:1、2、3
- 連結檔案 1:
- 包含建立時的
Parquet file 1
時間戳,以及附加數據的記錄。
- 包含建立時的
插入作業
請考慮插入作業發生時會發生什麼情況:插入手邊值4
為 之產品C
的新數據列。 這項作業會導致建立新的 Parquet 檔案和鏈接檔案,因此現在有兩個 Parquet 檔案和兩個鏈接檔案。
- Parquet 檔案 1:
- ProductID:A、B、C
- StockOnHand:1、2、3
- Parquet 檔案 2:
- ProductID:D
- StockOnHand: 4
- 連結檔案 1:
- 包含建立時的
Parquet file 1
時間戳,以及附加數據的記錄。
- 包含建立時的
- 連結檔案 2:
- 包含建立時的
Parquet file 2
時間戳,以及附加數據的記錄。
- 包含建立時的
此時,Delta 數據表的查詢會傳回下列結果。 結果從多個 Parquet 檔案來源並不重要。
ProductID | StockOnHand |
---|---|
A | 1 |
B | 2 |
C | 3 |
D | 4 |
每次後續的插入作業都會建立新的 Parquet 檔案和鏈接檔案。 這表示 Parquet 檔案和連結檔案的數目隨著每個插入作業而成長。
更新作業
現在,請考慮更新作業發生時會發生什麼情況:產品 D
的數據列已將其庫存值變更為 10
。 這項作業會導致建立新的 Parquet 檔案和鏈接檔案,因此現在有三個 Parquet 檔案和三個鏈接檔案。
- Parquet 檔案 1:
- ProductID:A、B、C
- StockOnHand:1、2、3
- Parquet 檔案 2:
- ProductID:D
- StockOnHand: 4
- Parquet 檔案 3:
- ProductID:C
- StockOnHand:10
- 連結檔案 1:
- 包含建立時的
Parquet file 1
時間戳,以及附加數據的記錄。
- 包含建立時的
- 連結檔案 2:
- 包含建立時的
Parquet file 2
時間戳,以及附加數據的記錄。
- 包含建立時的
- 連結檔案 3:
- 包含建立時的
Parquet file 3
時間戳,以及記錄數據已更新。
- 包含建立時的
此時,Delta 數據表的查詢會傳回下列結果。
ProductID | StockOnHand |
---|---|
A | 1 |
B | 2 |
C | 10 |
D | 4 |
產品 C
的數據現在存在於多個 Parquet 檔案中。 不過,Delta 數據表的查詢會結合連結檔案,以判斷應該使用哪些數據來提供正確的結果。
刪除作業
現在請考慮刪除作業發生時會發生什麼事:刪除產品 B
的數據列。 這項作業會產生新的 Parquet 檔案和鏈接檔案,因此現在有四個 Parquet 檔案和四個鏈接檔案。
- Parquet 檔案 1:
- ProductID:A、B、C
- StockOnHand:1、2、3
- Parquet 檔案 2:
- ProductID:D
- StockOnHand: 4
- Parquet 檔案 3:
- ProductID:C
- StockOnHand:10
- Parquet 檔案 4:
- ProductID:A、C、D
- StockOnHand:1、10、4
- 連結檔案 1:
- 包含建立時的
Parquet file 1
時間戳,以及附加數據的記錄。
- 包含建立時的
- 連結檔案 2:
- 包含建立時的
Parquet file 2
時間戳,以及附加數據的記錄。
- 包含建立時的
- 連結檔案 3:
- 包含建立時的
Parquet file 3
時間戳,以及記錄數據已更新。
- 包含建立時的
- 連結檔案 4:
- 包含建立時的
Parquet file 4
時間戳,並記錄已刪除數據。
- 包含建立時的
請注意, Parquet file 4
不再包含產品 B
的數據,但它確實包含數據表中所有其他數據列的數據。
此時,Delta 數據表的查詢會傳回下列結果。
ProductID | StockOnHand |
---|---|
A | 1 |
C | 10 |
D | 4 |
注意
此範例很簡單,因為它牽涉到小型數據表、只是一些作業,而且只有次要修改。 體驗許多寫入作業且包含許多數據列的大型數據表,每個版本會產生一個以上的 Parquet 檔案。
重要
視您定義 Delta 資料表的方式和資料修改作業的頻率而定,可能會導致許多 Parquet 檔案。 請注意,每個 Fabric 容量授權都有 護欄。 如果 Delta 數據表的 Parquet 檔案數目超過 SKU 的限制,查詢會 回復為 DirectQuery,這可能會導致查詢效能變慢。
若要管理 Parquet 檔案的數目,請參閱 本文稍後的 Delta 數據表維護 。
差異時間移動
鏈接檔案會啟用查詢數據,從先前的時間點開始。 這項功能稱為 差異時間移動。 先前的時間點可能是時間戳或版本。
請考慮下列查詢範例。
SELECT * FROM Inventory TIMESTAMP AS OF '2024-04-28T09:15:00.000Z';
SELECT * FROM Inventory AS OF VERSION 2;
提示
您也可以使用 @
速記語法來查詢資料表,將時間戳或版本指定為數據表名稱的一部分。 時間戳的格式必須為 yyyyMMddHHmmssSSS
。 您可以在 之後 @
指定版本,方法是在 版本前面加上 v
。
以下是使用速記語法重寫的先前查詢範例。
SELECT * FROM Inventory@20240428091500000;
SELECT * FROM Inventory@v2;
重要
使用時間移動存取的數據表版本是由事務歷史記錄檔的保留閾值和 VACUUM 作業的頻率和指定保留的組合來決定(稍後在 Delta 數據表維護 一節中說明)。 如果您每天以預設值執行 VACUUM,則會有七天的數據可供時間移動。
框架
框架 是 Direct Lake 作業,可設定應該用來將數據載入語意模型數據行的 Delta 資料表版本。 同樣重要的是,版本也會決定載入數據時應該排除的內容。
框架作業會將每個 Delta 資料表的時間戳/版本戳記到語意模型數據表中。 此時,當語意模型需要從 Delta 數據表載入數據時,會使用與最新框架作業相關聯的時間戳/版本來判斷要載入的數據。 自從忽略最新的框架作業之後,Delta 數據表所發生的任何後續數據修改(直到下一個框架作業為止)。
重要
因為框架語意模型參考特定的 Delta 數據表版本,所以來源必須確定它會保留 Delta 數據表版本,直到完成新版本的框架為止。 否則,當使用者需要由模型存取 Delta 資料表檔案,且已由產生者工作負載進行清理或刪除時,就會發生錯誤。
如需框架的詳細資訊,請參閱 Direct Lake 概觀。
資料表資料分割
可以分割差異數據表,以便將數據列子集儲存在單一 Parquet 檔案集中。 分割區可以加速查詢和寫入作業。
假設 Delta 數據表有一十億個銷售數據列,為期兩年。 雖然可以將所有數據儲存在單一 Parquet 檔案集中,但對於此數據磁碟區而言,讀取和寫入作業並不理想。 相反地,透過將數十億個數據列分散到多個 Parquet 檔案,即可改善效能。
設定數據表數據分割時,必須定義分割區索引鍵。 數據分割索引鍵會決定要儲存在哪一個數列中的數據列。 對於 Delta 資料表,資料分割索引鍵可以根據指定資料行(或數據行)的相異值來定義,例如日期數據表的月/年數據行。 在此情況下,兩年的數據會分散到24個分割區(2年 x12個月)。
網狀架構計算引擎不知道數據表數據分割。 當他們插入新的分割區索引鍵值時,會自動建立新的分割區。 在 OneLake 中,您會找到每個唯一分割區索引鍵值的一個子資料夾,而每個子資料夾會儲存自己的一組 Parquet 檔案和鏈接檔案。 至少必須有一個 Parquet 檔案和一個連結檔案存在,但每個子資料夾中的實際檔案數目可能會有所不同。 隨著數據修改作業的進行,每個分割區都會維護自己的一組 Parquet 檔案和鏈接檔案,以追蹤指定時間戳或版本傳回的專案。
如果已分割差異數據表的查詢只篩選為最近三個月的銷售數據,則可以快速識別需要存取的 Parquet 檔案和鏈接檔案子集。 如此一來,即可完全略過許多 Parquet 檔案,進而提升讀取效能。
不過,不會篩選數據分割索引鍵的查詢可能不一定會執行得更好。 當 Delta 數據表將所有資料儲存在單一大型 Parquet 檔案集,而且有檔案或數據列群組片段時,就可能發生這種情況。 雖然可以在多個叢集節點之間平行處理從多個 Parquet 檔案擷取的數據,但許多小型 Parquet 檔案可能會對檔案 I/O 造成負面影響,因此查詢效能。 基於這個理由,最好避免在大部分情況下分割 Delta 數據表,除非寫入作業或擷取、轉換和載入 (ETL) 程式會從中明顯受益。
數據分割也有利於插入、更新和刪除作業,因為檔案活動只會發生在符合已修改或刪除數據列之數據分割索引鍵的子資料夾中。 例如,如果將一批數據插入數據分割的 Delta 數據表中,則會評估數據以判斷批次中存在的數據分割索引鍵值。 然後,數據只會導向至數據分割的相關資料夾。
瞭解差異數據表使用分割區的方式,可協助您設計最佳的 ETL 案例,以減少更新大型差異數據表時需要執行的寫入作業。 寫入效能可藉由減少必須建立的任何新 Parquet 檔案的數目和大小來改善。 針對依月份/年分割的大型 Delta 數據表,如上一個範例所述,新數據只會將新的 Parquet 檔案新增至最新的分割區。 先前行事曆月份的子資料夾仍維持不變。 如果必須修改前一個行事曆月份的任何數據,則只有相關的分割區資料夾會收到新的分割區和鏈接檔案。
重要
如果 Delta 數據表的主要用途是做為語意模型的數據源(第二種是其他查詢工作負載),通常最好避免將數據行載入優化 至記憶體中的喜好分割。
針對 Direct Lake 語意模型或 SQL 分析端點,優化 Delta 數據表數據分割的最佳方式是讓 Fabric 自動管理每個差異數據表版本的 Parquet 檔案。 將管理留給 Fabric 應該透過平行處理來產生高查詢效能,不過它不一定提供最佳寫入效能。
如果您必須針對寫入作業進行優化,請考慮使用分割區,根據分割區索引鍵將寫入作業優化至 Delta 數據表。 不過,請注意,在分割 Delta 數據表時,可能會對讀取效能造成負面影響。 基於這個理由,我們建議您仔細測試讀取和寫入效能,或許是建立相同 Delta 數據表的多個復本來比較計時。
警告
如果您在高基數數據行上分割,可能會導致過多的 Parquet 檔案。 請注意,每個 Fabric 容量授權都有 護欄。 如果 Delta 數據表的 Parquet 檔案數目超過 SKU 的限制,查詢會 回復為 DirectQuery,這可能會導致查詢效能變慢。
Parquet 檔案
Delta 數據表的基礎記憶體是一或多個 Parquet 檔案。 Parquet 檔案格式通常用於 寫入一次、讀取多 的應用程式。 每次修改 Delta 資料表中的數據時,都會建立新的 Parquet 檔案,無論是插入、更新或刪除作業。
注意
您可以使用工具存取與 Delta 數據表相關聯的 Parquet 檔案,例如 OneLake 檔案總管。 檔案可以下載、複製或移至其他目的地,就像移動任何其他檔案一樣容易。 不過,它是 Parquet 檔案與 JSON 鏈接檔案的組合,可讓計算引擎以 Delta 數據表的形式對檔案發出查詢。
Parquet 檔案格式
Parquet 檔案的內部格式與其他常見的數據儲存格式不同,例如 CSV、TSV、XMLA 和 JSON。 這些格式會依數據列組織數據,而 Parquet 則依數據行組織數據。 此外,Parquet 檔案格式與這些格式不同,因為它會將數據列組織成一或多個 數據列群組。
Power BI 語意模型的內部數據結構是以數據行為基礎,這表示 Parquet 檔案與 Power BI 共用很多共同點。 這種相似性表示 Direct Lake 語意模型可以有效率地將數據從 Parquet 檔案直接載入記憶體。 事實上,大量的數據可以在幾秒內載入。 將這項功能與「匯入」語意模型的重新整理形成對比,該模型必須擷取區塊或源數據,然後處理、編碼、儲存,然後將它載入記憶體中。 匯入語意模型重新整理作業也可以耗用大量的計算(記憶體和CPU),而且需要相當長的時間才能完成。 不過,使用 Delta 數據表,在產生 Parquet 檔案時,大部分準備適合直接載入語意模型的數據。
Parquet 檔案儲存數據的方式
請考慮下列範例數據集。
Date | ProductID | StockOnHand |
---|---|---|
2024-09-16 | A | 10 |
2024-09-16 | B | 11 |
2024-09-17 | A | 13 |
以 Parquet 檔案格式儲存時,概念上,此數據集看起來可能會像下列文字。
Header:
RowGroup1:
Date: 2024-09-16, 2024-09-16, 2024-09-17…
ProductID: A, B, A…
StockOnHand: 10, 11, 13…
RowGroup2:
…
Footer:
資料會藉由取代通用值的字典索引鍵來壓縮,並套用 執行長度編碼 (RLE) 。 RLE 會努力將一系列相同的值壓縮成較小的表示法。 在下列範例中,會在標頭中建立數值索引鍵與值的字典對應,並使用較小的索引鍵值來取代數據值。
Header:
Dictionary: [
(1, 2024-09-16), (2, 2024-09-17),
(3, A), (4, B),
(5, 10), (6, 11), (7, 13)
…
]
RowGroup1:
Date: 1, 1, 2…
ProductID: 3, 4, 3…
StockOnHand: 5, 6, 7…
Footer:
當 Direct Lake 語意模型需要數據來計算分組ProductID
的數據行總StockOnHand
和時,只需要與兩個數據行相關聯的字典和數據。 在包含許多數據行的大型檔案中,可以略過 Parquet 檔案的大量部分,以協助加速讀取程式。
注意
Parquet 檔案的內容不是人類可讀取的,因此它不適合在文本編輯器中開啟。 不過,有許多開放原始碼工具可供開啟並顯示 Parquet 檔案的內容。 這些工具也可以讓您檢查元數據,例如檔案中包含的數據列和數據列群組數目。
V 順序
網狀架構支援稱為 V-Order 的其他優化。 V 順序是 Parquet 檔案格式的寫入時間優化。 套用 V 順序之後,就會產生較小且更快速的檔案讀取。 此優化特別適用於 Direct Lake 語意模型,因為它會準備數據以快速載入記憶體,因此對容量資源的需求較少。 這也會導致查詢效能更快,因為需要掃描的記憶體較少。
由網狀架構專案建立和載入的差異數據表,例如 數據管線、 數據流和 筆記本 ,會自動套用 V 順序。 不過,上傳至 Fabric Lakehouse 或快捷方式所參考的 Parquet 檔案可能未套用此優化。 雖然仍可讀取非優化的 Parquet 檔案,但讀取效能可能不如套用 V 順序的對等 Parquet 檔案那麼快。
注意
套用 V 順序的 Parquet 檔案仍然符合開放原始碼 Parquet 檔案格式。 因此,非網狀架構工具可以讀取它們。
如需詳細資訊,請參閱 Delta Lake 資料表最佳化和 V 順序 (機器翻譯)。
差異數據表優化
本節說明優化語意模型差異數據表的各種主題。
資料量
雖然 Delta 數據表可以成長以儲存極大量的數據, 但 Fabric 容量防護會對 查詢它們的語意模型施加限制。 超過這些限制時,查詢會 回復為 DirectQuery,這可能會導致查詢效能變慢。
因此,請考慮藉由提高其數據粒度(儲存摘要數據)、減少維度或儲存較少的歷程記錄,來限制大型 事實數據表 的數據列計數。
此外,請確定 已套用 V 順序 ,因為它會產生更小且更快速的檔案進行讀取。
資料行資料類型
努力減少每個 Delta 資料表中每個數據行中的基數(唯一值數目)。 這是因為所有數據行都是使用 哈希編碼來壓縮和儲存的。 哈希編碼需要 V 順序優化,才能將數值標識符指派給數據行中包含的每個唯一值。 這是儲存的數值標識符,在記憶體和查詢期間需要哈希查閱。
當您使用 近似數值數據類型 時(例如 float 和 real),請考慮捨入值並使用較低的有效位數。
不必要的數據行
和任何數據表一樣,Delta 資料表應該只儲存所需的數據行。 在本文中,這表示語意模型所需的內容,不過可能有其他分析工作負載可查詢 Delta 數據表。
除了支援模型關聯性的數據行之外,差異數據表應包含語意模型篩選、分組、排序和摘要所需的數據行。 雖然不必要的數據行不會影響語意模型查詢效能(因為它們不會載入記憶體),但它們會產生較大的記憶體大小,因此需要更多計算資源來載入和維護。
由於 Direct Lake 語意模型不支援匯出數據行,因此您應該在 Delta 數據表中具體化這類數據行。 請注意,此設計方法是匯入和 DirectQuery 語意模型的反模式。 例如,如果您有 FirstName
和 LastName
數據行,而且需要數據 FullName
行,請在將數據列插入 Delta 資料表時具體化此資料行的值。
請考慮某些語意模型摘要可能相依於一個以上的數據行。 例如,若要計算銷售,模型中的量值會加總兩個數據行的乘積: Quantity
和 Price
。 如果這兩個數據行都未獨立使用,將銷售計算具體化為單一數據行會更有效率,而不是將其元件值儲存在不同的數據行中。
數據列群組大小
在內部,Parquet 檔案會將數據列組織成每個檔案內的多個數據列群組。 例如,包含 30,000 個數據列的 Parquet 檔案可能會將它們分成三個數據列群組,每個群組都有 10,000 個數據列。
數據列群組中的數據列數目會影響 Direct Lake 讀取數據的速度。 由於 I/O 過多,具有較少數據列的數據列群組數目可能會對將數據行數據載入語意模型中產生負面影響。
一般而言,我們不建議您變更預設的數據列群組大小。 不過,您可以考慮變更大型 Delta 數據表的數據列群組大小。 請務必仔細測試讀取和寫入效能,或許是建立具有不同組態的相同 Delta 數據表的多個復本來比較計時。
重要
請注意,每個 Fabric 容量授權都有 護欄。 如果 Delta 數據表的數據列群組數目超過 SKU 的限制,查詢會 回復到 DirectQuery,這可能會導致查詢效能變慢。
差異資料表維護
一段時間后,隨著寫入作業的發生,Delta 數據表版本會累積。 最後,您可能會到達對讀取效能產生負面影響的點。 更糟的是,如果每個數據表的 Parquet 檔案數目或每個數據表的數據列群組,或每個數據表的數據列超過 容量的護欄,查詢會 回復到 DirectQuery,這可能會導致查詢效能變慢。 因此,請務必定期維護 Delta 數據表。
最佳化
您可以使用 OPTIMIZE 將 Delta 數據表優化,將較小的檔案聯合成較大的檔案。 您也可以將 WHERE
子句設定為只以符合指定資料分割述詞的數據列篩選子集為目標。 僅支援涉及分割區索引鍵的篩選。 此命令 OPTIMIZE
也可以套用 V-Order 來壓縮和重寫 Parquet 檔案。
建議您定期在大型且經常更新的 Delta 數據表上執行此命令,或許每天都會在 ETL 程式完成時執行。 平衡更好的查詢效能與優化數據表所需的資源使用量成本之間的取捨。
真空
您可以使用 VACUUM 來移除不再參考和/或早於設定保留閾值的檔案。 請小心設定適當的保留期間,否則您可能會失去時間回溯到比語意模型數據表中加章的框架還舊版本的能力。
重要
因為框架語意模型參考特定的 Delta 數據表版本,所以來源必須確定它會保留 Delta 數據表版本,直到完成新版本的框架為止。 否則,當使用者需要由模型存取 Delta 資料表檔案,且已由產生者工作負載進行清理或刪除時,就會發生錯誤。
REORG TABLE
您可以使用 REORG TABLE 來重新組織 Delta 數據表 ,方法是重寫檔案以清除虛刪除的數據,例如當您使用 ALTER TABLE DROP COLUMN 卸除數據行時。
自動化數據表維護
若要自動化數據表維護作業,您可以使用 Lakehouse API。 如需詳細資訊,請參閱 使用 Microsoft Fabric REST API 管理 Lakehouse。
提示
您也可以在 Fabric 入口網站中使用 lakehouse 數據表維護功能 ,簡化 Delta 數據表的管理。