ออกแบบ event schema ใน BigQuery ยังไงให้ query ง่ายและไม่พังทีหลัง
หลายทีมเริ่มเก็บ event analytics ด้วยความตั้งใจที่ดีมาก
- อยากรู้ว่าผู้ใช้ทำอะไรบ้าง
- อยากวัด funnel
- อยากดู conversion
- อยากตาม operational events
- อยากดู behavior หลัง release
- อยากตอบคำถามของ product, ops, support และ management ได้เร็วขึ้น
ช่วงแรกการเริ่มเก็บ event มักดูง่าย แค่ส่งชื่อ event เข้าไปพร้อม payload บางอย่าง แล้วค่อยคิดเรื่อง query ทีหลัง แต่พอข้อมูลเริ่มโต ปัญหาจะค่อย ๆ โผล่มาเอง
ชื่อ event ไม่สม่ำเสมอ
field เดิมความหมายเปลี่ยนไปเรื่อย ๆ
ทีมหนึ่งส่ง userId อีกทีมส่ง user_id
บาง event มี order_id บาง event ใช้ orderId
timestamp มีหลายแบบ
payload ยืดหยุ่นเกินไปจน query ยาก
พอผ่านไปไม่กี่เดือน คนเริ่มไม่มั่นใจว่า query ที่เขียนกำลังตอบคำถามถูกเรื่องจริงหรือไม่
BigQuery ช่วยเรื่องการ query ข้อมูลจำนวนมากได้ดีมาก แต่ถ้า event schema ตั้งต้นไม่ดี ความเร็วของ engine ก็ช่วยได้แค่ระดับหนึ่ง เพราะปัญหาจริงจะกลายเป็นเรื่อง semantic debt มากกว่า performance อย่างเดียว
บทความนี้อธิบายว่า event schema ใน BigQuery ควรออกแบบอย่างไรให้ query ง่าย ใช้ต่อได้จริง และไม่สร้างหนี้ข้อมูลจนพังทีหลัง
TL;DR
สรุปให้สั้นที่สุด
event schema ที่ดีต้องทำให้ event แต่ละรายการตอบได้ชัดว่า ใคร ทำอะไร เมื่อไร ที่ไหน กับ resource อะไร และอยู่ใน flow ไหน
ถ้าจะเริ่มให้ถูก ควรมีอย่างน้อย
- ชื่อ event ที่เสถียรและสื่อความหมาย
- ชื่อ field ที่สม่ำเสมอ
- timestamp ที่ชัด
- actor / resource / context identifiers ที่ตามเรื่องได้
- partitioning ตามเวลา
- การแยก event-level columns ออกจาก nested metadata อย่างมีวินัย
- schema governance แบบง่ายแต่จริง
ถ้าเริ่มเก็บแบบ “ใส่ JSON อะไรก็ได้ เดี๋ยวค่อย query ทีหลัง” วันหนึ่ง query จะเริ่มยากและทีมจะเริ่มไม่เชื่อข้อมูลของตัวเอง
ก่อนออกแบบ ต้องถามก่อนว่า event นี้ถูกเก็บไปเพื่ออะไร
ปัญหาที่เจอบ่อยคือทีมเริ่มเก็บ event โดยยังไม่ชัดว่าใครจะใช้ และใช้ตอบคำถามแบบไหน
คำถามที่ควรถามก่อนมีประมาณนี้
- event นี้ใช้ตอบคำถาม product analytics หรือ operational analytics
- ใครจะ query ข้อมูลนี้
- query ส่วนใหญ่จะดูรายวัน รายสัปดาห์ หรือย้อนหลังยาว ๆ
- ต้อง trace รายการเดียวให้ครบ flow หรือเน้น aggregate trends
- ต้องเชื่อมกับ user, session, order, payment หรือ job execution อะไรบ้าง
- ต้องการ near-realtime แค่ไหน
- มี PII หรือข้อมูลอ่อนไหวอยู่หรือไม่
คำถามพวกนี้สำคัญ เพราะ event schema ที่ดีไม่ได้เริ่มจาก field เยอะที่สุด แต่เริ่มจากการรู้ว่าจะตอบคำถามอะไรให้คนใช้งานจริง
Event schema ที่ดีควรตอบคำถามพื้นฐานอะไรได้บ้าง
ถ้าจะสรุปให้เป็นหลักง่าย ๆ event ที่ใช้งานได้ดีควรตอบคำถามเหล่านี้ให้ได้
- เกิดอะไรขึ้น
- เกิดเมื่อไร
- ใครเป็นคนทำ หรือ actor คืออะไร
- เกิดกับ resource ไหน
- เกิดในระบบหรือ flow ไหน
- เกิดจาก request ไหนหรือ correlation ไหน
- อยู่ใน tenant / environment / service ไหน
- มี properties สำคัญอะไรเพิ่มที่ช่วยให้วิเคราะห์ต่อได้
ถ้า event ตอบคำถามเหล่านี้ไม่ชัด เวลา query จะเริ่มต้องเดา และเมื่อทีมเริ่มเดาไม่ตรงกัน data layer จะเริ่มเสื่อมความน่าเชื่อถือ
เริ่มจาก naming ก่อน เพราะนี่คือจุดที่พังง่ายที่สุด
สิ่งที่ดูเล็กที่สุดแต่มักทำให้ระบบ analytics พังเร็วที่สุดคือชื่อ event และชื่อ field
ตัวอย่าง event naming ที่เริ่มพาไปลำบาก เช่น
clickButtonuser_do_checkoutpaymentDonerefund_okopenpagesuccess
ปัญหาคือชื่อเหล่านี้ไม่ชัดว่ากำลังอธิบายเหตุการณ์ในระดับไหน และทีมอื่นจะตีความต่างกันได้ง่าย
แนวทางที่อ่านง่ายกว่าและคุมได้ดีกว่ามักเป็น pattern แบบนี้
user_signed_upquote_createdpayment_succeededrefund_requestedrefund_approveddocument_uploadedjob_completedorder_status_changed
ข้อสำคัญไม่ใช่ว่าต้องใช้รูปแบบไหนเป๊ะ แต่ต้อง ใช้แบบเดียวกันทั้งระบบ
ตั้งชื่อ event ให้สื่อความหมายเชิงธุรกิจ ไม่ใช่แค่ชื่อปุ่ม
นี่สำคัญมาก
ถ้าคุณตั้ง event ตาม UI element มากเกินไป เช่น
submit_button_clickedblue_cta_clickedtab_2_opened
ข้อมูลจะเริ่มตอบคำถามเชิงธุรกิจยากขึ้นเรื่อย ๆ เพราะ UI เปลี่ยนได้ตลอด และชื่อ event จะหลุดจากความหมายของระบบจริง
ในหลายกรณีสิ่งที่ควรวัดคือ business action เช่น
quote_requestedcheckout_startedpayment_succeededclaim_document_uploadedadmin_user_role_changed
ถ้าจำเป็นต้องเก็บ interaction ระดับ UI จริง ก็ควรทำให้แยกชั้นจาก event เชิงธุรกิจให้ชัด ไม่เช่นนั้น dataset จะเริ่มปนกันเร็วมาก
Field names ต้องสม่ำเสมอแบบน่าเบื่อให้ได้
นี่คือเรื่องที่ทีมมักเบื่อแต่สำคัญที่สุดในระยะยาว
ถ้าระบบหนึ่งส่ง userId อีกระบบส่ง user_id
ระบบหนึ่งใช้ createdAt อีกระบบใช้ event_time
ระบบหนึ่งใช้ paymentStatus อีกระบบใช้ status
ในวันแรกมันดูเล็กมาก แต่พอ query ข้าม event หลายชุด งานจะเริ่มช้าทั้งในแง่ performance และในแง่ความคิด เพราะ analyst ต้องจำ dialect ของแต่ละ event family เอง
แนวทางที่ดีกว่าคือกำหนด field naming convention กลาง เช่น
- ใช้
snake_case - ใช้
event_name - ใช้
event_timestamp - ใช้
user_id - ใช้
tenant_id - ใช้
resource_type - ใช้
resource_id - ใช้
request_id - ใช้
correlation_id
ความสม่ำเสมอแบบนี้ช่วยมากกว่าการพยายามทำ schema ให้ฉลาดเกินไป
Core columns ที่ควรมีเกือบทุก event
ในหลายระบบ คุณจะคุมคุณภาพได้ดีขึ้นมากถ้ามี “event envelope” กลางที่ใช้ร่วมกันเกือบทุก event
ตัวอย่าง columns ที่มักควรมี เช่น
event_nameevent_timestampevent_dateactor_typeactor_idresource_typeresource_idtenant_idenvironmentservice_namerequest_idcorrelation_idsession_idmetadataหรือpropertiesสำหรับรายละเอียดเฉพาะ event
ไม่ได้แปลว่าทุก field ต้อง non-null เสมอไป แต่การมี envelope กลางทำให้ query ข้ามโดเมนง่ายขึ้นมาก
event_timestamp ต้องมีอันเดียวที่เป็น canonical
อีกปัญหาที่เจอบ่อยคือเวลาใน event มีหลายค่าและไม่มีใครรู้ว่าอันไหนควรใช้เป็นหลัก เช่น
created_atsent_atreceived_atinserted_atclient_timeserver_time
แนวทางที่ดีคือกำหนดให้ชัดว่า field ไหนคือ canonical event time เช่น
event_timestamp= เวลาที่ระบบถือว่าเหตุการณ์นี้เกิดขึ้นจริงในเชิงธุรกิจหรือ ingestion policy ที่ตกลงกัน
แล้วค่อยมี field เสริมถ้าจำเป็น เช่น
received_atprocessed_atclient_timestamp
ถ้าไม่มีจุดยึดกลาง เวลา query ตามวันหรือทำ funnel จะเริ่มเพี้ยนง่ายมาก
แนะนำให้มี event_date แยกด้วย
แม้ BigQuery จะ query จาก timestamp ได้ แต่การมี event_date เป็น DATE แยกไว้จะช่วยให้ query, partitioning และ dashboard logic หลายอย่างง่ายขึ้น
ตัวอย่างเช่น
- filter ช่วงวัน
- group by รายวัน
- partition pruning
- scheduled aggregations
event_date จึงมักคุ้มที่จะมีเป็น first-class column แยกจาก event_timestamp
แยก actor ออกจาก resource ให้ชัด
event จำนวนมากเริ่ม query ยากเพราะไม่แยกว่าใครเป็นผู้กระทำ และอะไรคือสิ่งที่ถูกกระทำ
ตัวอย่างเช่น event refund_approved
สิ่งที่ควรตอบให้ชัดคือ
- actor คือใคร เช่น
admin_7 - resource คืออะไร เช่น
refund: rf_1001
ถ้าคุณเก็บแค่ user_id ลอย ๆ ในทุก event วันหนึ่ง query จะเริ่มสับสนว่า field นี้หมายถึง user เจ้าของ resource หรือ user คนที่กด action กันแน่
แนวทางที่ดีกว่าคือแยกเป็น
actor_typeactor_idresource_typeresource_id
สิ่งนี้ช่วยมากเวลา query ข้ามโดเมนและเวลาอธิบายข้อมูลกับทีมอื่น
request_id และ correlation_id ควรมาอยู่ใน event schema ด้วย
นี่คือ field ที่หลายทีมข้ามไป แต่พอมี incident หรืออยาก trace flow ข้าม systems จะเสียดายมาก
ถ้า event schema มี
request_idcorrelation_id
คุณจะ query สิ่งเหล่านี้ได้ง่ายขึ้น เช่น
- request ไหนสร้าง event sequence นี้
- failure นี้ผูกกับ flow ไหน
- payment event, webhook event และ worker event อยู่ในเรื่องเดียวกันหรือไม่
- incident หนึ่งกระทบ events กลุ่มใดบ้าง
สำหรับ operational analytics และ debugging ข้าม service field สองตัวนี้มีค่ามากกว่าที่ดูเผิน ๆ
เมื่อไรควรใช้ nested / repeated fields
BigQuery รองรับ nested และ repeated fields ได้ดี ซึ่งมีประโยชน์มากถ้าใช้อย่างมีวินัย
มันเหมาะกับกรณีเช่น
- metadata ย่อยที่ไม่จำเป็นต้องเป็น top-level columns ทุกตัว
- arrays ของ attributes
- context groups เช่น device info, location info, request context
- objects ที่มีโครงสร้างค่อนข้างเสถียร
ตัวอย่างเช่น
actorobjectresourceobjectcontextobjectdeviceobject
แต่ข้อควรระวังคืออย่าใช้ nested แบบ “โยนทุกอย่างลงไปก้อนเดียวแล้วค่อย query เอาเอง” เพราะจะทำให้ discoverability และ consistency แย่ลง
แนวคิดที่ดีคือ
- field ที่ใช้ filter/join/group บ่อย ควรอยู่ top-level
- field ที่เป็นรายละเอียดเฉพาะ event และไม่ใช่แกนหลักของ query ค่อยอยู่ nested
อย่าใช้ metadata เป็นหลุมดำของทุกอย่าง
หลายทีมเริ่มต้นด้วยการมี metadata หรือ properties แล้วทุกอย่างที่คิดไม่ออกก็โยนลงไปหมด
ช่วงแรกมันเร็วมาก แต่ระยะยาวจะเริ่มเกิดปัญหา
- field เดิมชื่อไม่เหมือนกันข้าม event
- ไม่มี schema governance
- analyst ต้องเปิดดูตัวอย่าง payload ก่อนทุกครั้ง
- query ซับซ้อนโดยไม่จำเป็น
- data quality checks ทำยาก
- documentation เริ่มตามไม่ทัน
metadata ควรมี แต่ไม่ควรกลายเป็นที่ซ่อนความไม่ชัดของ schema
หลักคิดง่าย ๆ คือ
- ถ้า field นี้สำคัญพอจะ filter, join, group หรือวัดผลบ่อย ควรดันขึ้นเป็น top-level
- ถ้า field นี้เป็นแค่รายละเอียดประกอบบาง event ค่อยอยู่ใน metadata
Partitioning ควรเริ่มยังไง
สำหรับ event tables ส่วนใหญ่ partition ตามเวลาเป็น baseline ที่ควรทำแทบเสมอ โดยมากก็มักเป็น event_date หรือ event_timestamp
เหตุผลไม่ได้มีแค่เรื่อง cost แต่รวมถึง
- query เร็วขึ้น
- สแกนน้อยลง
- retention จัดการง่าย
- scheduled processing คาดเดาได้ขึ้น
ถ้าคุณไม่ partition event table ตั้งแต่ต้น พอข้อมูลโตขึ้น query จะเริ่มแพงและการควบคุม workload จะยากขึ้นเรื่อย ๆ
Clustering ควรคิดจาก query patterns จริง
หลัง partition แล้ว field ที่อาจเหมาะกับ clustering มักเป็นพวกที่ใช้ filter บ่อย เช่น
event_nametenant_idactor_idresource_typeresource_id
แต่การเลือก cluster fields ควรมาจาก query patterns จริง ไม่ใช่ใส่ทุกอย่างที่ดูสำคัญพร้อมกัน
ถามง่าย ๆ ว่า
- คนชอบ filter จากอะไร
- dashboard ใช้ field ไหนบ่อย
- scheduled queries ชอบเริ่มจากเงื่อนไขอะไร
field เหล่านี้มักเป็นตัวเลือกที่ดีสำหรับ clustering
อย่าเก็บ event ทุกอย่างใน table เดียวเพียงเพราะทำได้
นี่เป็นเรื่องที่ต้องตัดสินใจอย่างมีสติ
การรวมทุก event ไว้ในตารางเดียวมีข้อดี เช่น query รวมง่าย, envelope กลางชัด, governance ง่ายขึ้นระดับหนึ่ง
แต่ถ้าระบบใหญ่มากและ event ต่างชนิดต่าง shape กันเกินไป table เดียวก็อาจกลายเป็นถังใหญ่ที่ดูแลงานยากขึ้น
แนวทางที่มักใช้ได้จริงคือ
- มี table หลักสำหรับ event envelope ที่ shape ใกล้เคียงกัน
- หรือแยก event families ตามโดเมน เช่น product events, operational events, audit events
สิ่งสำคัญคืออย่าแยกจนกระจัดกระจายเกินไป และอย่ารวมจน schema governance พัง
ออกแบบให้รองรับ additive changes ได้
event schema ที่ดีไม่ใช่ schema ที่ไม่เคยเปลี่ยน แต่คือ schema ที่เพิ่มได้โดยไม่พังง่าย
สิ่งที่ควรเลี่ยง เช่น
- เปลี่ยนความหมายของ field เดิมเงียบ ๆ
- เปลี่ยน type ของ field เดิม
- reuse field เดิมไปแทนความหมายใหม่
- เปลี่ยนชื่อ event เดิมโดยไม่มี migration plan
สิ่งที่มักปลอดภัยกว่า เช่น
- เพิ่ม optional fields ใหม่
- เพิ่ม nested properties ใหม่อย่างมีวินัย
- deprecate field เดิมก่อนลบ
- เก็บ changelog ของ event schema
analytics จะอยู่กับคุณยาวกว่าที่คิด ดังนั้น additive schema mindset สำคัญมาก
ตัวอย่าง schema แบบ practical
ตัวอย่างนี้เป็น event schema แบบกลางที่ใช้ต่อได้ดีในหลาย use case
create table analytics.events (
event_name string not null,
event_timestamp timestamp not null,
event_date date not null,
actor_type string,
actor_id string,
resource_type string,
resource_id string,
tenant_id string,
environment string,
service_name string,
request_id string,
correlation_id string,
session_id string,
metadata json
)
partition by event_date
cluster by event_name, tenant_id;
schema นี้ยังไม่สมบูรณ์สำหรับทุกระบบ แต่ช่วยให้เห็นหลักสำคัญคือ
- มี envelope กลาง
- มี canonical time
- มี actor / resource separation
- มี request context
- ยังเปิดพื้นที่ให้ metadata อยู่ แต่ไม่ปล่อยให้ทุกอย่างอยู่ในนั้นทั้งหมด
ตัวอย่าง event records
{
"event_name": "payment_succeeded",
"event_timestamp": "2026-04-18T10:21:04Z",
"event_date": "2026-04-18",
"actor_type": "user",
"actor_id": "usr_1024",
"resource_type": "payment",
"resource_id": "pay_8001",
"tenant_id": "tenant_acme",
"environment": "production",
"service_name": "payments-api",
"request_id": "req_9f13f2",
"correlation_id": "corr_checkout_1001",
"session_id": "sess_8821",
"metadata": {
"currency": "THB",
"amount": 1250,
"provider": "2c2p"
}
}
{
"event_name": "document_uploaded",
"event_timestamp": "2026-04-18T10:25:11Z",
"event_date": "2026-04-18",
"actor_type": "user",
"actor_id": "usr_1024",
"resource_type": "document",
"resource_id": "doc_5561",
"tenant_id": "tenant_acme",
"environment": "production",
"service_name": "documents-api",
"request_id": "req_91baf0",
"correlation_id": "corr_claim_404",
"session_id": "sess_8821",
"metadata": {
"mime_type": "application/pdf",
"storage_provider": "gcs",
"status": "pending_scan"
}
}
ตัวอย่างแบบนี้ query trend, funnel, and trace flows ได้ง่ายกว่าการมี payload แบบหลวม ๆ มาก
ตัวอย่าง query ที่ schema ดีจะช่วยทันที
ตัวอย่างเช่นหายอด event รายวันแยกตาม event_name
select
event_date,
event_name,
count(*) as total_events
from analytics.events
where event_date between '2026-04-01' and '2026-04-18'
group by event_date, event_name
order by event_date, event_name;
หรือ query ตาม correlation flow
select
event_timestamp,
event_name,
service_name,
resource_type,
resource_id
from analytics.events
where correlation_id = 'corr_checkout_1001'
order by event_timestamp;
หรือดู document uploads ที่ยัง pending_scan
select
resource_id,
actor_id,
event_timestamp,
metadata
from analytics.events
where event_name = 'document_uploaded'
and json_value(metadata, '$.status') = 'pending_scan';
schema ที่ดีทำให้ query แบบนี้เป็นเรื่องตรงไปตรงมา ไม่ต้องใช้การแกะ payload แบบเดาไปเรื่อย ๆ
Governance แบบเบาที่ควรมีตั้งแต่ต้น
คุณไม่จำเป็นต้องมี data governance committee ตั้งแต่วันแรก แต่ควรมีอย่างน้อย
- รายการ event names กลาง
- naming convention กลาง
- field dictionary สั้น ๆ
- owner ของ schema แต่ละโดเมน
- policy ว่าอะไรขึ้น top-level ได้
- policy ว่า event ใหม่ต้องประกอบด้วยอะไรบ้าง
- changelog ของ schema changes
สิ่งเหล่านี้ช่วยมากกว่าการหวังว่าทุกคนจะตั้งชื่อเหมือนกันเอง
ข้อผิดพลาดที่เจอบ่อย
1) เก็บ payload เป็น JSON อย่างเดียวทุกอย่าง
ทำให้ query สำคัญช้าและอ่านยากโดยไม่จำเป็น
2) ไม่มี canonical timestamp
สุดท้ายแต่ละคนใช้เวลาไม่เหมือนกัน และ dashboard ตอบคนละเรื่อง
3) field names ไม่สม่ำเสมอ
ทำให้ query ข้ามโดเมนยากมาก
4) เอา UI interactions กับ business events ปนกันแบบไร้โครง
สุดท้าย dataset ใหญ่ขึ้นแต่ความหมายพร่า
5) เปลี่ยน semantics ของ field เดิมเงียบ ๆ
อันนี้อันตรายกว่าลบ field ตรง ๆ เพราะ query เก่าอาจยังรันได้ แต่ตอบผิด
Internal links และ discoverability ก็สำคัญ
เมื่อ event schema เริ่มเยอะ การค้นว่า “มี event อะไรให้ใช้บ้าง” จะสำคัญขึ้นเรื่อย ๆ ถ้า schema ดีแต่ไม่มีเอกสารหรือ mapping ที่ discoverable คนในทีมก็ยังใช้ยาก
อย่างน้อยควรมีหน้าหรือ document ที่ช่วยตอบว่า
- event อะไรอยู่ในโดเมนไหน
- event ไหนใช้วัด funnel นี้
- field ไหนเป็น canonical
- correlation ระหว่าง event families เป็นอย่างไร
data model ที่ดีต้องค้นเจอและทำความเข้าใจได้ง่ายด้วย ไม่ใช่แค่ technically query ได้
รีวิวเชิง production-minded
Correctness
event schema ที่ดีช่วยให้ query ตอบคำถามทางธุรกิจได้ถูกเรื่องมากขึ้น ไม่ใช่แค่รันผ่าน ซึ่งสำคัญกว่าความเร็วอย่างเดียวในระยะยาว
Security
ยิ่ง event analytics โต ยิ่งต้องคิดเรื่อง PII และ access control ให้ชัดว่า field ไหนควรเก็บ, ใครควรเห็น, และอะไรควรถูก mask หรือแยกออก
Efficiency
top-level columns ที่สม่ำเสมอ, partitioning ที่ถูกต้อง และ metadata ที่ไม่มั่ว ช่วยให้ query ทั้งเร็วขึ้นและอ่านง่ายขึ้น พร้อมกัน
Error handling
ถ้า schema governance ไม่ดี ปัญหาจะไม่โผล่เป็น error ตรง ๆ แต่จะโผล่เป็น “query ได้แต่ตอบผิด” ซึ่งอันตรายกว่า เพราะทีมอาจตัดสินใจจากข้อมูลที่เพี้ยนโดยไม่รู้ตัว
Checklist สั้น ๆ ก่อนปล่อย event schema ใช้งานจริง
- event name สื่อความหมายเชิงธุรกิจชัด
- field naming convention ใช้เหมือนกันทั้งระบบ
- มี
event_timestampเป็น canonical time - มี
event_dateสำหรับ partition/query ใช้ง่าย - แยก
actor_*ออกจากresource_* - มี
request_idและcorrelation_idเมื่อเหมาะสม - field ที่ใช้ filter/join/group บ่อยอยู่ top-level
metadataไม่ถูกใช้เป็นหลุมดำของทุกอย่าง- partitioning และ clustering อิง query patterns จริง
- มี field dictionary หรือ schema guide กลาง
- มี policy สำหรับ additive changes และ deprecation
บทความที่ควรอ่านต่อ
- BigQuery vs PostgreSQL งาน analytics แบบไหนควรแยกไป data warehouse
- BigQuery Cost Control Checklist: partition, cluster, prune และกัน query แพง
- Request ID และ Correlation ID คืออะไร และช่วย debug production ยังไง
- Internal Linking สำหรับ technical articles ควรวางยังไงให้ทั้งคนและ Google เข้าใจ
สรุป
event schema ใน BigQuery ที่ดีไม่ได้เกิดจากการใส่ field ให้เยอะที่สุด แต่เกิดจากการกำหนด envelope ที่ชัด ตั้งชื่อให้สม่ำเสมอ และรู้ว่าอะไรควรเป็น top-level field อะไรควรอยู่เป็น metadata
ถ้าคุณเริ่มต้นดี query จะง่ายขึ้น, cost จะคุมง่ายขึ้น, incident tracing จะดีขึ้น และทีมจะเชื่อข้อมูลมากขึ้น แต่ถ้าเริ่มต้นแบบปล่อยให้ payload โตตามใจ วันหนึ่งปัญหาจะไม่ใช่แค่ query ช้า แต่จะเป็นการที่ไม่มีใครมั่นใจว่าข้อมูลกำลังบอกอะไรแน่
สรุปสั้นที่สุดคือ
event schema ที่ดีต้องทำให้ทั้งเครื่อง query ได้ง่าย และคนอ่านเข้าใจตรงกันว่า event นั้นหมายถึงอะไร