Power BI 6 — Import, DirectQuery, Composite & VertiPaq
Power BI 6 — Import, DirectQuery, Composite & VertiPaq
Khi bạn kéo một field vào visual, đằng sau nó Power BI phải lấy dữ liệu từ đâu đó. "Đâu đó" chính là chế độ lưu trữ (storage mode) của bảng. Đây là quyết định kiến trúc quan trọng nhất của một mô hình: nó chi phối tốc độ, độ tươi của dữ liệu, kích thước model, và cả những gì bạn được phép viết bằng DAX/M.
Bài này đi sâu vào engine nén cột VertiPaq, ba chế độ cốt lõi (Import, DirectQuery, Direct Lake), cách kết hợp chúng bằng Composite model + Dual + Aggregations, kỹ thuật incremental refresh cho bảng lớn, và cuối cùng là lý do vì sao một measure lại chậm — câu chuyện Formula Engine vs Storage Engine.
Nếu bạn chưa nắm mô hình sao (star schema) và quan hệ, hãy đọc trước Mô hình dữ liệu. Phần query folding sẽ nối tiếp Power Query (M).
1. VertiPaq — engine nén cột in-memory
Trước khi bàn chế độ nào, phải hiểu thứ khiến Import nhanh đến khó tin: VertiPaq (còn gọi là xVelocity), engine lưu trữ của Power BI / Analysis Services Tabular.
Khác với cơ sở dữ liệu OLTP lưu theo dòng (row-store), VertiPaq lưu theo cột (columnar) và nén rất mạnh trong RAM. Vì analytics thường chỉ đọc vài cột trên hàng triệu dòng (ví dụ SUM(Sales[Amount]) chỉ cần đúng một cột), lưu theo cột giúp:
- Chỉ quét đúng cột cần thiết, bỏ qua phần còn lại.
- Dữ liệu cùng cột thường giống nhau → nén cực tốt.
Hai kỹ thuật nén cốt lõi:
- Dictionary encoding: mỗi giá trị khác nhau trong cột được gán một số nguyên (ID). Bảng chỉ lưu dãy ID nhỏ gọn thay vì chuỗi/số gốc. Cột
Countryvới 200 giá trị chỉ cần ~8 bit/dòng. - RLE (Run-Length Encoding): nếu cột đã được sắp xếp và có nhiều giá trị lặp liên tiếp, VertiPaq lưu "giá trị X lặp N lần" thay vì N bản sao. Rất hiệu quả với cột có ít giá trị phân biệt và đã sort.
Yếu tố quyết định kích thước và tốc độ là cardinality — số giá trị phân biệt của một cột:
- Cột cardinality thấp (giới tính, trạng thái, tháng) nén tuyệt vời, dictionary nhỏ.
- Cột cardinality cao (ID giao dịch, timestamp tới giây, khóa GUID) nén kém, dictionary khổng lồ, làm phình model và làm chậm mọi phép quét/join.
Đây chính là lý do trong Mô hình dữ liệu ta khuyên tách cột datetime thành Date + Time riêng, và tránh mang các cột "rác" cardinality cao vào model. Một cột cao cardinality không dùng đến có thể chiếm phần lớn dung lượng file .pbix.
Ghi nhớ: trong Import, mỗi cột thừa là chi phí RAM thật. Cắt cột không dùng và giảm cardinality là cách tối ưu rẻ nhất.
2. Import mode — nhanh nhất, đánh đổi độ tươi
Import nạp toàn bộ dữ liệu vào model, nén bằng VertiPaq, và giữ trong RAM. Mọi truy vấn của visual chạy trực tiếp trên bản sao in-memory này — không chạm tới nguồn.
Ưu điểm:
- Nhanh nhất. Không có độ trễ mạng tới nguồn, dữ liệu đã nén tối ưu cho analytics.
- Toàn bộ DAX và M khả dụng. Không giới hạn hàm, không lo query folding.
- Nguồn được "giải phóng": dashboard đông người xem không tạo tải lên database sản xuất.
Đánh đổi:
- Độ trễ dữ liệu (data latency). Dữ liệu chỉ mới tính đến lần refresh gần nhất. Trên Power BI service, refresh theo lịch (Pro tối đa 8 lần/ngày, Premium/PPU 48 lần/ngày).
- Giới hạn dung lượng model. Model phải vừa RAM. Giới hạn phụ thuộc license (Pro ~1 GB/model; Premium/PPU lớn hơn nhiều tùy dung lượng dung tích). Bảng vài trăm triệu dòng có thể vượt ngưỡng.
- Refresh toàn bộ bảng lớn có thể tốn hàng chục phút tới nhiều giờ — đây là lúc cần incremental refresh (mục 6).
Chọn Import khi: dữ liệu vừa RAM, refresh vài lần/ngày là đủ tươi, cần hiệu năng tương tác tốt nhất. Đây là mặc định nên chọn cho đại đa số dashboard.
3. DirectQuery — dữ liệu mới, đánh đổi tốc độ
DirectQuery không nạp dữ liệu. Model chỉ lưu metadata (schema, quan hệ, measure). Mỗi lần visual cần số liệu, Power BI sinh câu SQL và gửi tới nguồn ngay lúc đó (query at runtime).
-- (minh hoạ) Một visual "Doanh thu theo tháng" trong DirectQuery
-- Power BI tự dịch thành SQL kiểu:
SELECT d.[Month], SUM(f.[Amount]) AS [Revenue]
FROM [Fact_Sales] f
JOIN [Dim_Date] d ON f.[DateKey] = d.[DateKey]
GROUP BY d.[Month];
Ưu điểm:
- Dữ liệu gần real-time. Mỗi thao tác đọc trạng thái mới nhất của nguồn — không cần refresh model.
- Model rất lớn. Không phải nạp vào RAM, nên có thể "phủ" bảng hàng tỷ dòng nằm trong data warehouse.
Đánh đổi (quan trọng):
- Chậm hơn Import, thường rõ rệt. Mỗi lát cắt (slicer), mỗi cross-filter đều bắn một hoặc nhiều query xuống nguồn. Trải nghiệm chỉ nhanh khi nguồn được tối ưu.
- Phụ thuộc hoàn toàn vào nguồn. Nguồn nghẽn/chậm thì report chậm; nguồn down thì report chết. Dashboard đông người có thể đè tải lên database.
- Hạn chế DAX/M. Nhiều hàm DAX phức tạp và biến đổi M không thể dịch được thành SQL sẽ bị chặn hoặc gây fallback tốn kém.
- Cần query folding. Mọi biến đổi trong Power Query phải "fold" được thành SQL — nếu bước M không fold, DirectQuery không dùng được bảng đó. (Xem lại Power Query (M).)
Cảnh báo hiệu năng: DirectQuery không làm report nhanh hơn — nó đánh đổi tốc độ lấy độ tươi và quy mô. Đừng chọn DirectQuery chỉ vì "nghe hiện đại". Nếu chọn, bạn bắt buộc phải tối ưu nguồn: index/partition, materialized view, giảm cột. Kỹ năng đọc kế hoạch thực thi ở series tối ưu SQL với EXPLAIN là hành trang cần thiết.
Chọn DirectQuery khi: yêu cầu độ tươi gần real-time bắt buộc, hoặc dữ liệu quá lớn không thể Import, và bạn kiểm soát được hiệu năng nguồn.
4. Composite model & Dual — kết hợp cả hai
Bạn không phải chọn "hoặc/hoặc" cho cả model. Composite model cho phép mỗi bảng có storage mode riêng — trộn Import và DirectQuery trong cùng một model.
Mỗi bảng có một trong ba storage mode:
- Import — luôn nằm trong VertiPaq (cache).
- DirectQuery — luôn truy vấn nguồn.
- Dual — bảng "song tính": tùy ngữ cảnh mà xử sự như Import hoặc như DirectQuery.
Vì sao Dual là mấu chốt? Xét mô hình sao có bảng fact khổng lồ để DirectQuery (chi tiết, dữ liệu mới) và các bảng dimension chung như Date, Product, Geography.
- Nếu dimension để Import: khi join với fact DirectQuery, Power BI phải kéo danh sách khóa từ Import ra rồi truyền xuống nguồn — sinh SQL cồng kềnh, chậm.
- Nếu để DirectQuery: mọi slicer trên dimension (kể cả khi không đụng fact) đều bắn query xuống nguồn — lãng phí.
- Đặt Dual: khi bảng được truy vấn cùng fact DirectQuery, nó xử sự như DirectQuery (join gọn trong một câu SQL); khi truy vấn độc lập (chỉ điền slicer), nó xử sự như Import (đọc từ cache, tức thì). Đây là "the secret sauce" của composite và aggregation.
Lưu ý về Dual:
- Bảng Dual phải chạy được ở chế độ DirectQuery, nghĩa là các bước M phải fold được. M phức tạp không fold → không đặt Dual được.
- Cache phía Import của bảng Dual có thể stale: nó chỉ tươi tới lần refresh gần nhất khi hành xử như Import, nhưng lấy dữ liệu live khi hành xử như DirectQuery. Cần đồng bộ lịch refresh cẩn thận.
Khi nào dùng Composite: khi cần cả hiệu năng của phần tổng hợp Import lẫn khả năng drill xuống chi tiết/độ tươi của DirectQuery — dẫn thẳng tới aggregations.
5. Aggregations — bảng tổng hợp Import đè lên chi tiết DirectQuery
Mẫu hình mạnh nhất của composite: user-defined aggregations.
Ý tưởng: đa số câu hỏi của người dùng ở mức tổng hợp ("doanh thu theo tháng theo vùng"), chỉ một số ít cần drill tới từng giao dịch. Vậy:
- Bảng chi tiết (fact hàng tỷ dòng) để DirectQuery — không nạp RAM.
- Bảng aggregation (đã group sẵn theo tháng/vùng/danh mục, nhỏ gọn) để Import trong VertiPaq — cực nhanh.
- Dimension chung để Dual.
Power BI tự động định tuyến: nếu một truy vấn có thể trả lời từ bảng aggregation (đúng granularity), nó "hit" aggregation và trả về từ Import in-memory — nhanh như Import. Nếu truy vấn cần chi tiết mà agg không có (miss), nó fallback xuống DirectQuery nguồn. Người dùng không cần biết — họ chỉ thấy phần lớn tương tác rất nhanh.
Mẫu điển hình: một bảng agg Import phủ ~80% truy vấn thường gặp (rollup theo tháng, theo danh mục), còn bảng chi tiết DirectQuery lo 20% drill-through còn lại.
Nguyên tắc thiết kế aggregation: đặt granularity trùng với cách người dùng thực sự phân tích, dùng agg tiết kiệm để không phình RAM, và luôn để dimension chung ở Dual.
6. Incremental refresh — chỉ nạp phần mới/đổi
Với bảng giao dịch lớn ở chế độ Import, refresh toàn bộ mỗi lần là lãng phí và có thể mất hàng giờ. Incremental refresh giải quyết bằng cách phân vùng (partition) theo thời gian và chỉ refresh phần cần thiết.
Cách hoạt động:
- Trong Power Query, tạo hai tham số Date/Time tên
RangeStartvàRangeEnd(đúng tên, phân biệt hoa thường), rồi lọc cột ngày của bảng theo khoảng[RangeStart, RangeEnd). Filter này phải fold xuống nguồn. - Định nghĩa policy: lưu trữ (store) bao nhiêu — ví dụ 5 năm lịch sử; và refresh (refresh) bao nhiêu — ví dụ chỉ 10 ngày gần nhất.
- Khi publish lên service và refresh lần đầu, service tự tạo các partition: partition lịch sử (nạp một lần) và partition tăng trưởng (refresh mỗi lần). Service tự thay giá trị
RangeStart/RangeEndcho từng partition.
Kết quả: lần đầu nạp toàn bộ lịch sử; các lần sau chỉ chạm cửa sổ gần nhất → refresh vốn mất hàng giờ rút xuống vài phút, tải lên nguồn giảm mạnh. Có thể kèm partition DirectQuery real-time cho dữ liệu nóng nhất (mô hình hybrid table).
Điều kiện bắt buộc: query folding. Nếu filter ngày không fold xuống nguồn, nguồn vẫn trả toàn bộ dữ liệu rồi mới lọc trong bộ nhớ — mất sạch lợi ích.
Dùng cho: bảng fact giao dịch lớn, chỉ thêm dòng mới (append) và ít sửa dữ liệu cũ — bán hàng, log, giao dịch tài chính.
7. Direct Lake (Microsoft Fabric) — hướng đi mới
Direct Lake là chế độ lưu trữ của semantic model trong Microsoft Fabric, đọc trực tiếp các bảng Delta/Parquet trong OneLake (lakehouse), không copy dữ liệu vào cache riêng của model.
Cách hoạt động: VertiPaq đọc thẳng các file Delta trong OneLake. Khi một cột được chạm lần đầu, engine transcode nó sang định dạng in-memory của VertiPaq (dictionary/encoding), rồi thực thi aggregate/join. Cột đã "warm" nên truy vấn sau nhanh gần như Import; nếu thiếu RAM, cột "nguội" bị page out (thiết kế cho dữ liệu "lớn hơn bộ nhớ").
Refresh chủ yếu là thao tác metadata: pipeline ETL ghi file Delta mới (commit version mới), model thực hiện reframe — cập nhật con trỏ tới version Delta mới nhất và làm mất hiệu lực cache. Không phải nạp lại toàn bộ.
Lợi ích: tốc độ gần Import mà không nạp trước toàn bộ, độ tươi gần real-time kiểu DirectQuery mà không đẩy mọi query xuống database — không nhân bản dữ liệu.
Đây là định hướng chiến lược của Microsoft khi hợp nhất mọi thứ quanh OneLake. Direct Lake yêu cầu Fabric (F-SKU) và dữ liệu ở dạng Delta trong lakehouse. Từ 2025, có thể tạo model Direct Lake ngay trong Power BI Desktop và trộn bảng từ nhiều nguồn. Nếu tổ chức bạn đang cân nhắc Fabric, đây là hướng đáng theo dõi.
8. So sánh Import vs DirectQuery vs Direct Lake
| Tiêu chí | Import | DirectQuery | Direct Lake (Fabric) |
|---|---|---|---|
| Dữ liệu lưu ở đâu | VertiPaq in-memory (copy) | Chỉ metadata, ở nguồn | Delta/Parquet ở OneLake, đọc trực tiếp |
| Tốc độ truy vấn | Nhanh nhất | Chậm hơn, phụ thuộc nguồn | Gần Import (sau warm cột) |
| Độ tươi dữ liệu | Tới lần refresh gần nhất | Gần real-time | Gần real-time (reframe) |
| Quy mô model | Giới hạn RAM/license | Rất lớn | Rất lớn ("bigger than memory") |
| Tải lên nguồn | Chỉ khi refresh | Mỗi thao tác visual | Chủ yếu là metadata reframe |
| DAX/M | Đầy đủ | Hạn chế | Gần đầy đủ (như Import) |
| Query folding | Không bắt buộc | Bắt buộc | Không áp dụng (đọc Delta) |
| Yêu cầu nền tảng | Bất kỳ | Nguồn tương thích DQ | Fabric + OneLake (Delta) |
| Nên dùng khi | Mặc định, đa số dashboard | Cần real-time + dữ liệu quá lớn | Đã dùng Fabric, cần cả nhanh & tươi |
9. Formula Engine vs Storage Engine — vì sao measure chậm
Khi một measure DAX chạy chậm, thủ phạm nằm ở một trong hai lớp của engine:
- Storage Engine (SE) — VertiPaq (hoặc SQL nếu DirectQuery). Lớp này quét, lọc, group, aggregate dữ liệu. Nó đa luồng, rất nhanh, và có thể cache kết quả. Các phép tổng hợp đơn giản (
SUM,COUNT, group by) được đẩy hết xuống đây. - Formula Engine (FE) — bộ máy tính logic DAX. Nó xử lý những gì SE không làm được: iterator phức tạp, logic hàng-theo-hàng, xử lý context transition rối. FE thường đơn luồng và không cache giữa các truy vấn.
Nguyên tắc: đẩy càng nhiều việc xuống Storage Engine càng tốt. Một measure chậm thường vì buộc Formula Engine phải xử lý quá nhiều dòng (ví dụ iterator lồng nhau lớn, CALCULATE tạo hàng loạt phép quét riêng lẻ, "materialize" bảng trung gian khổng lồ). Triệu chứng: thời gian dồn vào FE, SE nhàn rỗi.
Công cụ chẩn đoán: Performance Analyzer trong Desktop, và DAX Studio để xem server timings — tách rõ thời gian FE và SE, đếm số SE query. Kỹ thuật viết DAX gọn để tối ưu FE/SE được đề cập ở DAX & Time Intelligence.
Use case thực tế
Tình huống A — Dashboard dữ liệu lớn cần độ tươi cao. Đội vận hành cần theo dõi giao dịch "gần như tức thì" trên một bảng fact hàng tỷ dòng nằm trong data warehouse, nhưng vẫn muốn tương tác mượt cho các báo cáo tổng hợp thường ngày.
- Giải pháp composite + aggregations: bảng chi tiết để DirectQuery (độ tươi + quy mô), bảng agg group theo ngày/vùng/danh mục để Import (tốc độ), dimension chung để Dual.
- Đa số câu hỏi tổng hợp hit agg → nhanh như Import; drill xuống chi tiết fallback DirectQuery → vẫn tươi.
- Bắt buộc: query folding cho bảng DQ/Dual, và tối ưu nguồn (index/partition) — dùng EXPLAIN để soi kế hoạch.
- Nếu tổ chức đã có Fabric/OneLake: cân nhắc Direct Lake để có gần như cả hai (nhanh + tươi) mà không cần dàn composite phức tạp.
Tình huống B — Bảng giao dịch lớn, chỉ append. Bảng Fact_Sales 5 năm, mỗi ngày thêm dòng mới, gần như không sửa dữ liệu cũ. Refresh toàn bộ mất hơn 2 giờ.
- Giải pháp Import + incremental refresh:
RangeStart/RangeEndlọc cột ngày (fold xuống nguồn); policy lưu 5 năm, refresh 7–10 ngày gần nhất. - Refresh hằng ngày chỉ chạm partition mới nhất → rút từ vài giờ xuống vài phút, giảm tải nguồn.
Ghi nhớ
- Mặc định chọn Import. Nó nhanh nhất, đầy đủ DAX/M. Chỉ rời khỏi Import khi có lý do rõ ràng (dữ liệu quá lớn hoặc cần real-time).
- VertiPaq sống bằng cardinality thấp. Cắt cột thừa, giảm cột cao cardinality — đây là tối ưu rẻ và hiệu quả nhất.
- DirectQuery đổi tốc độ lấy độ tươi + quy mô. Nó không tự nhanh; bạn phải tối ưu nguồn và đảm bảo query folding.
- Composite + Dual + Aggregations là cách "ăn cả hai": tổng hợp nhanh (Import) + chi tiết/tươi (DirectQuery). Dimension chung để Dual.
- Incremental refresh là bắt buộc cho bảng Import lớn kiểu append — cần query folding để có tác dụng.
- Direct Lake (Fabric/OneLake) là hướng hợp nhất: gần Import về tốc độ, gần real-time về độ tươi, không copy dữ liệu.
- Measure chậm? Kiểm tra Formula Engine vs Storage Engine bằng DAX Studio — đẩy việc xuống SE, tránh bắt FE materialize bảng khổng lồ.
Nguồn tham khảo (Microsoft Learn & cộng đồng):
- Direct Lake overview — Microsoft Learn
- Direct Lake vs Import — SQLBI (2025)
- Composite model guidance — Microsoft Learn
- Incremental refresh overview — Microsoft Learn
Bài liên quan: Mô hình dữ liệu · Power Query (M) · DAX & Time Intelligence · Tối ưu SQL với EXPLAIN
Bài viết liên quan
Phân biệt ước lượng điểm và ước lượng khoảng, cách xây khoảng tin cậy (CI) bằng margin of error z*·SE / t*·SE, đánh đổi mức 90/95/99%, và cách DIỄN GIẢI ĐÚNG khoảng tin cậy (95% CI không phải xác suất tham số nằm trong khoảng). Có CI cho trung bình và cho tỷ lệ, ảnh hưởng của cỡ mẫu, cùng ví dụ ngân hàng về tỷ lệ nợ xấu và số dư trung bình.
Kimball dimensional modeling: bảng fact/dimension, star vs snowflake, grain, và Slowly Changing Dimension.
Khối OLAP, các thao tác drill-down/roll-up/slice & dice/pivot, OLAP vs OLTP và ROLAP/MOLAP/HOLAP.
Từ nguồn dữ liệu qua ETL/ELT vào Data Warehouse, Data Mart đến dashboard; staging, ODS, batch vs streaming.