- ClickHouse giới thiệu kiểu JSON mới để tránh nút thắt khi lưu tài liệu JSON dưới dạng chuỗi rồi phải phân tích lại mỗi lần, bằng cách đặt giá trị theo từng đường dẫn JSON vào kho lưu trữ cột thực thụ
- Trọng tâm của triển khai là các kiểu Variant và Dynamic; ngay cả khi cùng một đường dẫn JSON chứa các kiểu khác nhau như số nguyên, chuỗi hay mảng, hệ thống cũng không ép chúng hợp nhất vào một kiểu chung tối thiểu
max_dynamic_paths có giá trị mặc định là 1024, max_dynamic_types mặc định là 32 để giới hạn số lượng subcolumn và tệp theo từng kiểu, qua đó kiểm soát việc tăng file descriptor và chi phí merge
- Có thể điều chỉnh cách lưu trữ theo từng đường dẫn bằng type hint,
SKIP, SKIP REGEXP, và có thể đọc giá trị bằng cú pháp subcolumn như C.a.b
- Kiểu mới hướng tới thay thế
Object('json') đã deprecated, đồng thời lộ trình vẫn còn các cải tiến để dùng đường dẫn khóa JSON trong khóa chính hoặc data-skipping index
Bài toán đưa JSON vào lưu trữ dạng cột
- JSON được dùng như định dạng chung để xử lý dữ liệu bán cấu trúc và phi cấu trúc trong log, observability, streaming dữ liệu thời gian thực, kho lưu trữ ứng dụng di động và pipeline machine learning
- ClickHouse là một cơ sở dữ liệu hướng cột thực thụ, lưu bảng dưới dạng tập hợp các tệp dữ liệu cột trên đĩa để thực hiện nén và lọc/tổng hợp được vector hóa
- Để đạt cùng hiệu năng với JSON, thay vì lưu tài liệu vào cột chuỗi rồi phân tích sau, cần lưu giá trị của từng đường dẫn JSON duy nhất như các cột
Bốn ràng buộc mà kiểu JSON mới xử lý
-
Lưu trữ dạng cột theo từng đường dẫn
- Giá trị của từng đường dẫn JSON cũng phải được nén và có thể lọc/tổng hợp theo cách vector hóa như cột thông thường kiểu số
-
Kiểu dữ liệu thay đổi động
- Cùng một đường dẫn JSON
a có thể chứa các kiểu khác nhau như số nguyên, số thực hoặc mảng
- ClickHouse không thể biết trước điều này và các kiểu có thể không tương thích với nhau, nên nếu gộp về một kiểu chung tối thiểu thì có thể làm mất thông tin
-
Ngăn bùng nổ số lượng tệp cột
- Nếu mỗi đường dẫn JSON mới đều tạo một tệp cột mới, số lượng tệp trên đĩa sẽ tăng vọt với dữ liệu có nhiều khóa duy nhất
- File descriptor tiêu tốn bộ nhớ, và càng nhiều tệp cần xử lý thì hiệu năng merge cũng càng bị ảnh hưởng
-
Lưu trữ đặc các khóa thưa
- Khi có nhiều khóa JSON duy nhất nhưng thưa, không nên lặp lại việc lưu
NULL hay giá trị mặc định cho mọi hàng không có giá trị
- Chỉ nên lưu trữ đặc các giá trị thực tế để còn mở rộng được ở quy mô phân tích PB
Kiểu Variant: nền tảng không ép hợp nhất kiểu
- Kiểu dữ liệu Variant là một tính năng độc lập có thể dùng ngoài JSON, cho phép lưu và đọc các giá trị có kiểu dữ liệu khác nhau trong một cột của bảng
- Các cột ClickHouse truyền thống có kiểu cố định, và giá trị chèn vào phải thuộc kiểu đó hoặc được chuyển đổi ngầm định
- Cột
Nullable dùng tệp mask NULL ngoài tệp giá trị
Array lưu kích thước mảng trong tệp riêng, từ đó tính offset
- Cột Variant lưu các giá trị cùng kiểu cụ thể trong các subcolumn theo từng kiểu
- Ví dụ: mọi giá trị
Int64 được lưu trong C.Int64.bin, mọi giá trị String được lưu trong C.String.bin
- Mỗi hàng đang dùng kiểu nào được theo dõi bằng cột discriminator
UInt8
- Giá trị discriminator là chỉ số trong danh sách tên kiểu đã sắp xếp
- discriminator
255 là giá trị dành riêng cho NULL
- Thiết kế này khiến Variant có tối đa 255 kiểu cụ thể
- Các tệp dữ liệu theo kiểu dùng cấu trúc lưu trữ đặc chỉ chứa các hàng có giá trị
- Tệp theo kiểu không lưu giá trị
NULL
- Để tìm vị trí hàng trong tệp kiểu thực tế từ hàng discriminator, hệ thống dùng cột offset
UInt64 trong bộ nhớ
- Offset này không được lưu trên đĩa mà có thể tạo tức thời từ tệp cột discriminator
- Variant hỗ trợ lồng nhau tùy ý
- Thứ tự kiểu trong
Variant(T1, T2) và Variant(T2, T1) có cùng ý nghĩa
- Có thể lồng Variant bên trong Variant
- Có thể đọc giá trị của một kiểu lồng cụ thể bằng cách nối tên kiểu như subcolumn
Kiểu Dynamic: lưu được khi chưa biết trước danh sách kiểu
- Kiểu Dynamic là tính năng độc lập được xây dựng trên Variant và cũng có thể dùng ngoài ngữ cảnh JSON
- Dynamic bổ sung hai khả năng cho Variant
- Lưu các giá trị có kiểu tùy ý trong một cột mà không cần chỉ định trước danh sách kiểu
- Có thể giới hạn số lượng kiểu sẽ được lưu trong các tệp dữ liệu cột riêng
- Cách lưu trữ nội bộ giống Variant nhưng có thêm tệp
C.dynamic_structure.bin
- Tệp này chứa danh sách các kiểu được lưu dưới dạng subcolumn và thống kê kích thước tệp dữ liệu cột theo từng kiểu
- Metadata này được dùng khi đọc subcolumn và merge các data part
Dynamic(max_types=N) giới hạn số kiểu được lưu ở tệp riêng
0 <= N < 255
- Giá trị mặc định là 32
- Khi chạm giới hạn, các giá trị của những kiểu còn lại sẽ được lưu trong một tệp cột duy nhất như
C.SharedVariant.bin
- Kiểu của tệp này là
String
- Mỗi hàng chứa giá trị chuỗi theo cấu trúc
<binary_encoded_data_type><binary_value>
- Nhờ đó có thể lưu và đọc lại nhiều kiểu giá trị trong một tệp cột duy nhất
- Dynamic cũng dùng tên kiểu như subcolumn để đọc giá trị kiểu cụ thể, giống Variant
Khai báo kiểu JSON và cấu trúc lưu trữ
- Kiểu JSON mới lưu các đối tượng JSON có cấu trúc tùy ý và cho phép đọc từng giá trị JSON dưới dạng subcolumn dựa trên đường dẫn
- Khai báo kiểu có thể có tham số tùy chọn và hint
<column_name> JSON(
max_dynamic_paths=N,
max_dynamic_types=M,
some.path TypeName,
SKIP path.to.skip,
SKIP REGEXP 'paths_regexp')
max_dynamic_paths
- Mặc định là 1024
- Chỉ định số lượng đường dẫn khóa JSON sẽ được lưu trong các subcolumn riêng
- Các đường dẫn vượt giới hạn sẽ được lưu cùng nhau trong một subcolumn duy nhất có cấu trúc đặc biệt
max_dynamic_types
- Mặc định là 32
- Phạm vi giá trị là từ
0 đến 254
- Chỉ định số lượng kiểu dữ liệu sẽ được lưu trong các tệp dữ liệu cột riêng bên trong cột của một đường dẫn khóa JSON
- Các kiểu mới vượt giới hạn sẽ được lưu cùng nhau trong một tệp dữ liệu cột duy nhất có cấu trúc đặc biệt
some.path TypeName
- Đây là type hint cho một đường dẫn JSON cụ thể
- Đường dẫn đó sẽ luôn được lưu thành subcolumn với kiểu đã chỉ định, nhờ vậy bảo đảm hiệu năng
SKIP path.to.skip
- Bỏ qua một đường dẫn JSON cụ thể trong quá trình phân tích
- Đường dẫn đó sẽ không được lưu trong cột JSON
- Nếu đường dẫn chỉ định là một đối tượng JSON lồng nhau, toàn bộ đối tượng lồng nhau sẽ bị bỏ qua
SKIP REGEXP 'path_regexp'
- Bỏ qua các đường dẫn khớp với biểu thức chính quy trong quá trình phân tích JSON
- Các đường dẫn khớp sẽ không được lưu trong cột JSON
Cách đọc đường dẫn JSON như cột
- Giá trị của mỗi đường dẫn leaf duy nhất trong cột JSON được lưu trên đĩa theo một trong hai cách
- Các đường dẫn có type hint được lưu trong các tệp dữ liệu cột thông thường
- Các đường dẫn có thể thay đổi kiểu động được lưu trong subcolumn Dynamic
- Kiểu JSON dùng một tệp đặc biệt tên là
object_structure
- Tệp này chứa metadata cho các đường dẫn động
- Nó cũng chứa thống kê giá trị non-null của từng đường dẫn động
- Metadata này được dùng khi đọc subcolumn và merge các data part
- Sự bùng nổ tệp cột được kiểm soát bằng giới hạn hai tầng
max_dynamic_types giới hạn số kiểu được lưu vào tệp riêng trong một đường dẫn khóa JSON
max_dynamic_paths giới hạn số đường dẫn khóa JSON được lưu thành subcolumn riêng
- Các đường dẫn JSON động bổ sung vượt quá giới hạn
max_dynamic_paths sẽ được lưu thành shared data
- Các tệp ví dụ gồm
C.object_shared_data.size0.bin, C.object_shared_data.paths.bin, C.object_shared_data.values.bin
object_shared_data.values có kiểu String
- Mỗi mục có cấu trúc
<binary_encoded_data_type><binary_value>
- Với shared data,
object_structure.bin cũng lưu thêm thống kê
- Hiện tại hệ thống lưu thống kê giá trị non-null cho 10000 đường dẫn đầu tiên trong số các đường dẫn đang được lưu ở cột shared data
Cú pháp đường dẫn JSON và đối tượng lồng nhau
- Kiểu JSON cho phép đọc giá trị leaf của từng đường dẫn dưới dạng subcolumn dựa trên tên đường dẫn
- Giá trị của đường dẫn không được chỉ định type hint sẽ luôn có kiểu Dynamic
- Ví dụ: kiểu của
C.a.d là Dynamic
- Subcolumn kiểu con của Dynamic được đọc bằng cú pháp JSON đặc biệt
- Có thể đọc đối tượng JSON lồng nhau như subcolumn kiểu JSON bằng cú pháp
JSON_column.^some.path
- Hiện tại cú pháp dấu chấm không đọc đối tượng lồng nhau vì lý do hiệu năng
- Cấu trúc lưu trữ hiện tại hiệu quả cho việc đọc giá trị literal theo từng đường dẫn
- Nếu đọc toàn bộ đối tượng con theo từng đường dẫn sẽ phải đọc nhiều dữ liệu hơn nên có thể chậm
- Muốn trả về đối tượng thì cần cú pháp
.^
- ClickHouse có kế hoạch hợp nhất hai dạng cú pháp
. này
Tuần tự hóa discriminator dạng compact
- Nhiều đường dẫn JSON động có thể hầu hết chỉ chứa một kiểu giá trị
- Khi có nhiều đường dẫn JSON duy nhất nhưng thưa, tệp discriminator của mỗi đường dẫn chủ yếu sẽ chứa
255, tức giá trị NULL
- Các tệp như vậy nén tốt, nhưng nếu mọi giá trị trên toàn bộ hàng đều giống nhau thì vẫn còn nhiều lặp lại
- ClickHouse đã triển khai định dạng compact cho tuần tự hóa discriminator
- Thay vì thường xuyên ghi toàn bộ các giá trị discriminator
UInt8, nếu discriminator của cả granule mục tiêu đều giống nhau thì chỉ tuần tự hóa 3 giá trị
- chỉ dấu định dạng granule compact
- chỉ dấu số lượng giá trị của granule đó
- giá trị discriminator
- Tối ưu này được điều khiển bằng thiết lập MergeTree
use_compact_variant_discriminators_serialization
- Mặc định được bật
- Có những trường hợp chỉ lưu 3 giá trị thay vì 8192 giá trị theo index granularity thông thường
Trạng thái phát hành và bước tiếp theo
- Kiểu JSON mới được thiết kế để thay thế kiểu Object('json') đã deprecated
- Triển khai được cung cấp như tính năng experimental cho mục đích thử nghiệm trong bản phát hành ClickHouse 24.08
- Lộ trình JSON gồm các cải tiến để dùng đường dẫn khóa JSON trong khóa chính của bảng hoặc data-skipping index
- Các thành phần như Variant và Dynamic cũng là nền tảng để hỗ trợ thêm các kiểu bán cấu trúc khác như XML, YAML ngoài JSON
- Nếu người dùng ClickHouse Cloud muốn thử kiểu dữ liệu JSON mới, họ cần liên hệ đội ngũ hỗ trợ ClickHouse để yêu cầu quyền truy cập private preview
Chưa có bình luận nào.