Table.Buffer บังคับโหลดตารางลงหน่วยความจำและแยกออกจากแหล่งข้อมูลต้นทาง ช่วยป้องกันการ fold และควบคุมเวลาประมวลผล
= Table.Buffer(table as table, optional options as nullable record) as table
= Table.Buffer(table as table, optional options as nullable record) as table
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| table | Table | Yes | ตารางที่ต้องการบัฟเฟอร์ลงหน่วยความจำ | |
| options | Record | Optional | null | ตัวเลือก เช่น [BufferMode = BufferMode.Eager] (โหลดทันที) หรือ BufferMode.Delayed (โหลดเมื่อจำเป็น) |
let Source = Sql.Database("MyServer", "MyDatabase"), Orders = Source{[Item="Orders"]}[Data], Buffered = Table.Buffer(Orders) in Bufferedlet
Source = Sql.Database("MyServer", "MyDatabase"),
Orders = Source{[Item="Orders"]}[Data],
Buffered = Table.Buffer(Orders)
in
Buffered
ตารางข้อมูล Orders ทั้งหมดถูกโหลดลงหน่วยความจำ การเข้าถึงแหล่งข้อมูลหยุด
let Source = Excel.Workbook(File.Contents("C:\\Sales.xlsx")), SheetData = Source{[Item="Sheet1"]}[Data], Buffered = Table.Buffer(SheetData, [BufferMode = Buffer…let
Source = Excel.Workbook(File.Contents("C:\\Sales.xlsx")),
SheetData = Source{[Item="Sheet1"]}[Data],
Buffered = Table.Buffer(SheetData, [BufferMode = BufferMode.Eager])
in
Buffered
ข้อมูลจาก Excel ถูกโหลดลงหน่วยความจำทันทีที่ query ทำงาน
let Source = Web.Contents("https://api.example.com/data?limit=100000"), Json = Json.Document(Source), ToTable = Table.FromList(Json[results], Splitter.SplitByNo…let
Source = Web.Contents("https://api.example.com/data?limit=100000"),
Json = Json.Document(Source),
ToTable = Table.FromList(Json[results], Splitter.SplitByNothing()),
Buffered = Table.Buffer(ToTable),
AddIndex = Table.AddIndexColumn(Buffered, "Index", 1),
Filtered = Table.SelectRows(AddIndex, each [Index] <= 1000)
in
Filtered
ข้อมูล 100,000 แถวจาก API ถูกแคชลงหน่วยความจำก่อน จากนั้นจึงกรองเหลือ 1,000 แถว
let Source = Csv.Document(File.Contents("C:\\Data.csv"), [Delimiter=","]), ToTable = Table.FromList(Source, Splitter.SplitByNothing()), Buffered = Table.Buffer(…let
Source = Csv.Document(File.Contents("C:\\Data.csv"), [Delimiter=","]),
ToTable = Table.FromList(Source, Splitter.SplitByNothing()),
Buffered = Table.Buffer(ToTable),
Column1 = Table.SelectRows(Buffered, each [Column1] = "Active"),
Column2 = Table.SelectRows(Buffered, each [Column2] > 1000),
Combined = Table.Combine({Column1, Column2})
in
Combined
ข้อมูล CSV ถูก buffer ลังครั้งเดียว แล้วนำมาใช้ในหลาย operations
ผมคิดว่า StopFolding เป็น “ตัวเลิก” ส่วน Buffer เป็น “ตัวแคช” นะ StopFolding หยุดการ fold แต่ยังคงการเข้าถึง source ต่อไป ส่วน Buffer นั้นโหลดข้อมูลลงหน่วยความจำจริง ๆ ถ้าแค่อยากหยุด fold ให้ใช้ StopFolding เพราะเบากว่า ถ้าต้องการแยกข้อมูลออกจาก source ให้ใช้ Buffer
ผมมักใช้ Eager เวลาต้องการให้ข้อมูลโหลดทันที ส่วน Delayed นั้นปล่อยให้ Power Query โหลดตามความจำเป็นเท่านั้น Eager เหมาะสำหรับข้อมูลที่น้อย ๆ ต้องการแน่นอน ส่วน Delayed เหมาะสำหรับข้อมูลที่เยอะแต่อาจไม่ใช้ทั้งหมด
ได้จริง ผมเคยประสบ Buffer มีค่าใช้จ่าย memory ถ้าข้อมูลเยอะเกินไป มันอาจช้าแทนที่จะเร็ว ส่วนใหญ่ Buffer เหมาะสำหรับข้อมูลปานกลาง ถ้าข้อมูล 50 ล้าน rows ต้องคิดดูว่า buffer เสียคุ้มไหม
ผม buffer ได้แต่ scalar values เท่านั้น (ตัวเลข ข้อความ) ส่วน nested structures เช่น records, lists, tables ยังคงเป็น lazy references อยู่ นี่เรียกว่า shallow buffering
ผมแนะนำให้ buffer ตั้งแต่ต้นเลย ก่อนทำ transformation ใดลงมา ถ้า buffer ทีหลังอาจมีส่วนของข้อมูลไม่ถูก buffer นะ ดังนั้นที่ดีที่สุดคือใช้ Table.Buffer ขึ้นมาเร็วที่สุดในสูตร
Table.Buffer บังคับให้ Power Query โหลดข้อมูลตารางลงหน่วยความจำ (memory) ทั้งหมด แล้วตัดการเชื่อมต่อจากแหล่งต้นทาง
ที่เจ๋งคือสามารถป้องกันการ fold (folding) ไม่ให้คิวรี่ลงมา SQL Server ซ้ำ เมื่อคุณทำ Table.Buffer ข้อมูลจะถูก “ล็อก” ไว้ในหน่วยความจำ และการแปลงที่มาหลังจากนั้นจะทำงานกับข้อมูลที่โหลดแล้ว ไม่ได้ไปค้นหา source ใหม่
ส่วนตัวผมใช้ Table.Buffer บ่อย ๆ ในสองกรณี: (1) เมื่อข้อมูล SQL Server หรือ API เปลี่ยนแปลงตลอด – โหลดมาก่อนเพื่อให้ผลลัพธ์คงที่ (2) เมื่อคิวรี่ซับซ้อนมาก ๆ – buffer เข้าเพื่อลดภาระบน source ระวังอย่างเดียวคือ memory ถ้าข้อมูลเยอะเกินไป หรือใช้ Table.StopFolding ก็ได้ถ้าแค่อยากหยุด fold