Di industri game, aplikasi umumnya melakukan serialisasi data menggunakan Protobuf—kadang-kadang dengan kompresi zlib tambahan—lalu menyimpannya ke dalam kolom BLOB. Membaca data tersebut melalui SQL biasanya memerlukan komponen ETL eksternal atau deserialisasi di lapisan aplikasi, yang tidak praktis untuk debugging dan pengembangan perangkat lunak. Fitur readable Protobuf di PolarDB for MySQL menghilangkan kedua kebutuhan tersebut. Gunakan fungsi PROTO_TO_JSON() untuk mengonversi data BLOB menjadi JSON secara inline, lalu gunakan fungsi JSON standar MySQL (JSON_EXTRACT(), JSON_UNQUOTE()) untuk menyaring, membuat indeks, atau membuat kolom virtual berdasarkan data tersebut—semuanya dilakukan langsung dalam SQL.
Prasyarat
Sebelum memulai, pastikan Anda memiliki:
Kluster PolarDB for MySQL 8.0 yang menjalankan versi revisi 8.0.2.2.5 atau lebih baru. Untuk memeriksa versi Anda, lihat Kueri versi engine.
Cara kerja
PROTO_TO_JSON(blob_field) menerima kolom BLOB yang berisi data Protobuf ter-serialisasi dan mengembalikan string JSON. Fungsi ini secara otomatis menangani byte Protobuf mentah maupun byte Protobuf yang dikompresi zlib—tidak diperlukan perubahan pada kueri Anda untuk kedua kasus tersebut.
Setelah mengonversi data BLOB ke JSON, gunakan fungsi JSON standar MySQL untuk mengkueri bidang, membuat indeks, atau menghasilkan kolom virtual berdasarkan data Protobuf.
Konfigurasikan skema Protobuf untuk suatu kolom
Sebelum memanggil PROTO_TO_JSON(), kaitkan skema Protobuf dengan kolom BLOB menggunakan ALTER TABLE ... ALTER COLUMN. Langkah ini memberi tahu PolarDB for MySQL cara menginterpretasikan data biner dalam kolom tersebut.
Syntax:
ALTER TABLE table_name ALTER COLUMN column_name
[PROTO_NAME = 'protobuf_schema_name']
PROTO_TEXT = 'protobuf_schema_definition'
PROTO_MESSAGE = 'protobuf_message'
[COMPRESSION = 'zlib']Parameters:
| Parameter | Wajib | Deskripsi |
|---|---|---|
PROTO_NAME | Tidak | Nama untuk skema Protobuf. |
PROTO_TEXT | Ya | Definisi lengkap skema Protobuf. |
PROTO_MESSAGE | Ya | Jenis pesan Protobuf tingkat atas yang akan dideserialisasi. |
COMPRESSION | Tidak | Atur ke zlib jika data dikompresi dengan zlib sebelum ditulis ke kolom. Abaikan parameter ini untuk data yang tidak terkompresi. |
Data yang dikompresi zlib juga dapat didekompresi secara manual menggunakan UNCOMPRESS(), yang mengembalikan byte mentah dalam bentuk heksadesimal.Hapus skema Protobuf dari suatu kolom
Untuk menghapus skema, atur semua parameter skema ke string kosong:
ALTER TABLE table_name ALTER COLUMN column_name
PROTO_NAME=""
PROTO_TEXT=""
PROTO_MESSAGE='';Sebelum menghapus skema, pastikan kolom tersebut tidak lagi dirujuk oleh indeks atau kolom virtual apa pun.
Lihat skema Protobuf untuk suatu kolom
Aktifkan tampilan skema untuk sesi:
SET display_readable_proto_info = true;Tampilkan definisi kolom:
SHOW columns FROM table_name;
Contoh
Contoh berikut menggunakan skema addressbook.proto dari komunitas Protobuf untuk menjelaskan alur kerja lengkap: membuat tabel, mengonfigurasi skema, memasukkan data, dan mengkuerinya.
Skema yang digunakan dalam semua contoh:
syntax = "proto2";
package tutorial;
message Person {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}Langkah 1: Buat tabel
CREATE TABLE t1 (c1 INT, c2 BLOB);c2 berisi data Protobuf ter-serialisasi.
Langkah 2: Kaitkan skema ke kolom
Pilih pernyataan yang sesuai dengan apakah data Anda dikompresi atau tidak.
Tanpa kompresi zlib:
ALTER TABLE t1 ALTER COLUMN c2
PROTO_NAME="AddressBook"
PROTO_TEXT="syntax = \"proto2\";\n\npackage tutorial;\n\nmessage Person {\n optional string name = 1;\n optional int32 id = 2;\n optional string email = 3;\n\n enum PhoneType {\n MOBILE = 0;\n HOME = 1;\n WORK = 2;\n }\n\n message PhoneNumber {\n optional string number = 1;\n optional PhoneType type = 2 [default = HOME];\n }\n\n repeated PhoneNumber phones = 4;\n}\n\nmessage AddressBook {\n repeated Person people = 1;\n}"
PROTO_MESSAGE='AddressBook';Dengan kompresi zlib:
ALTER TABLE t1 ALTER COLUMN c2
PROTO_NAME="AddressBook"
PROTO_TEXT="syntax = \"proto2\";\n\npackage tutorial;\n\nmessage Person {\n optional string name = 1;\n optional int32 id = 2;\n optional string email = 3;\n\n enum PhoneType {\n MOBILE = 0;\n HOME = 1;\n WORK = 2;\n }\n\n message PhoneNumber {\n optional string number = 1;\n optional PhoneType type = 2 [default = HOME];\n }\n\n repeated PhoneNumber phones = 4;\n}\n\nmessage AddressBook {\n repeated Person people = 1;\n}"
PROTO_MESSAGE='AddressBook'
COMPRESSION='zlib';Langkah 3: Masukkan data
Tanpa kompresi zlib:
INSERT INTO t1 VALUES(1, X'0a380a0b56697375616c50726f746f10011a1776697375616c70726f746f40706f6c617264622e636f6d220e0a0a313233343536373839301002');Dengan kompresi zlib:
INSERT INTO t1 VALUES(1, X'3C000000785ee3b2e0e20ecb2c2e4dcc0928ca2fc9176094122f03730b405c8782fc9cc4a29424bde4fc5c253e2e2e432363135333730b4b03012600183d10de');Untuk memverifikasi byte terkompresi, dekompresi menggunakan UNCOMPRESS():
SELECT HEX(UNCOMPRESS(X'3C000000785ee3b2e0e20ecb2c2e4dcc0928ca2fc9176094122f03730b405c8782fc9cc4a29424bde4fc5c253e2e2e432363135333730b4b03012600183d10de')) AS UNCOMPRESS_DATA;Hasil:
+----------------------------------------------------------------------------------------------------------------------+
| UNCOMPRESS_DATA |
+----------------------------------------------------------------------------------------------------------------------+
| 0A380A0B56697375616C50726F746F10011A1776697375616C70726F746F40706F6C617264622E636F6D220E0A0A313233343536373839301002 |
+----------------------------------------------------------------------------------------------------------------------+Langkah 4: Baca dan kueri data
Baca data BLOB tanpa PROTO_TO_JSON()
Tanpa fitur readable Protobuf, mengkueri kolom c2 secara langsung mengembalikan data biner yang tidak dapat diinterpretasikan:
Tanpa kompresi zlib:
SELECT c2 FROM t1\GHasil:
*************************** 1. row ***************************
c2:
8
VisualProtovisualproto@polardb.com"
1234567890Dengan kompresi zlib:
SELECT c2 FROM t1\GHasil:
*************************** 1. row ***************************
c2: < x^...Output terkompresi berupa sampah biner yang tidak dapat dibaca secara langsung.
Baca data BLOB sebagai JSON
PROTO_TO_JSON() berfungsi baik untuk data terkompresi maupun tidak terkompresi—tidak diperlukan perubahan pada kueri Anda:
SELECT PROTO_TO_JSON(c2) FROM t1;Hasil:
+------------------------------------------------------------------------------------------------------------------------------------------+
| PROTO_TO_JSON(c2) |
+------------------------------------------------------------------------------------------------------------------------------------------+
| {"people": [{"id": 1, "name": "VisualProto", "email": "visualproto@polardb.com", "phones": [{"type": "WORK", "number": "1234567890"}]}]} |
+------------------------------------------------------------------------------------------------------------------------------------------+PROTO_TO_JSON() dapat membaca data baik yang dikompresi zlib maupun yang tidak terkompresi.Ekstrak bidang tertentu
Gunakan JSON_EXTRACT() untuk mengambil bidang individual dari output JSON:
SELECT JSON_EXTRACT(PROTO_TO_JSON(c2), '$.people[0].name') FROM t1;Hasil:
+-----------------------------------------------------+
| json_extract(PROTO_TO_JSON(c2), '$.people[0].name') |
+-----------------------------------------------------+
| "VisualProto" |
+-----------------------------------------------------+Buat indeks pada bidang Protobuf
Buat indeks fungsional pada bidang email:
CREATE INDEX i_email ON t1 ((CAST(JSON_UNQUOTE(JSON_EXTRACT(PROTO_TO_JSON(c2), '$.people[0].email')) AS CHAR(100))));Verifikasi bahwa indeks digunakan dengan menjalankan EXPLAIN:
EXPLAIN SELECT * FROM t1 WHERE CAST(JSON_UNQUOTE(JSON_EXTRACT(PROTO_TO_JSON(c2), '$.people[0].email')) AS CHAR(100)) = 'visualproto@polardb.com';Hasil:
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | t1 | NULL | ref | i_email | i_email | 403 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+Buat kolom virtual
Buat kolom virtual yang mengekspos bidang Protobuf sebagai kolom biasa:
ALTER TABLE t1 ADD COLUMN c3 VARCHAR(100) AS (JSON_EXTRACT(PROTO_TO_JSON(`c2`), _utf8mb4'$.people[0].email'));Verifikasi skema:
DESC t1;Hasil:
+-------+--------------+------+-----+---------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------------------+
| c1 | int(11) | YES | | NULL | |
| c2 | blob | YES | | NULL | |
| c3 | varchar(100) | YES | | NULL | VIRTUAL GENERATED |
+-------+--------------+------+-----+---------+-------------------+c3 adalah kolom virtual yang di-generate berdasarkan data Protobuf di c2.