全部产品
Search
文档中心

PolarDB:Kolom yang Dihasilkan

更新时间:Jul 06, 2025

Kolom yang dihasilkan adalah kolom yang nilainya merupakan hasil perhitungan dari suatu ekspresi. Topik ini menjelaskan cara membuat kolom yang dihasilkan dan membuat indeks pada kolom tersebut.

Buat kolom yang dihasilkan

Sintaksis

col_name data_type [GENERATED ALWAYS] AS (expr)
  [VIRTUAL | STORED | LOGICAL] [NOT NULL | NULL]
  [UNIQUE [KEY]] [[PRIMARY] KEY]
  [COMMENT 'string']

Anda dapat membuat jenis kolom yang dihasilkan berikut:

  • VIRTUAL: Nilai kolom tidak disimpan dan tidak memakan ruang penyimpanan. Nilai dihitung oleh node data setiap kali kolom dibaca.

    Catatan

    Jika Anda tidak menentukan tipe, kolom dengan tipe VIRTUAL akan dibuat secara default.

  • STORED: Nilai kolom dihitung oleh node data saat baris dimasukkan atau diperbarui. Hasilnya disimpan di node data dan memakan ruang penyimpanan.

  • LOGICAL: Mirip dengan STORED, nilai kolom dihitung saat baris dimasukkan atau diperbarui. Namun, nilai dihitung oleh node komputasi lalu disimpan sebagai kolom biasa di node data. Kolom LOGICAL dapat digunakan sebagai kunci partisi.

Pertimbangan

Fitur ini hanya didukung oleh instance PolarDB-X Enterprise Edition V5.4.17 atau yang lebih baru.

Mirip dengan kolom dalam MySQL, kolom yang dihasilkan memiliki batasan berikut dibandingkan dengan kolom biasa:

  • Batasan yang sama dengan MySQL

    • Anda tidak dapat menentukan nilai default untuk kolom yang dihasilkan.

    • Anda tidak dapat menetapkan atribut AUTO_INCREMENT untuk kolom yang dihasilkan atau merujuk ke kolom dengan atribut AUTO_INCREMENT.

    • Anda tidak dapat menggunakan fungsi deterministik seperti UUID(), CONNECTION_ID(), dan NOW() dalam ekspresi kolom yang dihasilkan.

    • Anda tidak dapat menggunakan variabel dalam ekspresi kolom yang dihasilkan.

    • Anda tidak dapat menggunakan subquery dalam ekspresi kolom yang dihasilkan.

    • Anda tidak dapat secara eksplisit menentukan nilai kolom yang dihasilkan dalam pernyataan INSERT dan UPDATE. Nilai kolom hanya dapat dihitung otomatis oleh database.

  • Batasan yang berbeda dari MySQL

    • Anda tidak dapat menambahkan kolom yang dihasilkan ke tabel yang telah mengaktifkan pengarsipan data dingin.

    • Kolom dengan tipe VIRTUAL atau STORED tidak dapat digunakan sebagai kunci partisi, kunci utama, atau kunci unik.

    • Anda tidak dapat merujuk fungsi tersimpan dalam kolom dengan tipe VIRTUAL atau STORED.

    • Jika indeks sekunder global mencakup kolom dengan tipe VIRTUAL atau STORED, indeks tersebut juga harus mencakup semua kolom yang dirujuk dalam ekspresinya.

    • Anda tidak dapat merujuk kolom dengan tipe VIRTUAL atau STORED dalam ekspresi kolom LOGICAL.

    • Anda tidak dapat mengubah tipe kolom LOGICAL atau kolom yang dirujuk dalam ekspresinya.

    • Hanya tipe berikut yang dapat digunakan untuk kolom LOGICAL dan kolom yang dirujuk dalam ekspresinya:

      • Tipe integer (BIGINT, INT, MEDUMINT, SMALLINT, TINYINT).

      • Tipe tanggal (DATETIME, DATE, TIMESTAMP). Kolom tipe tanggal dengan atribut ON UPDATE CURRENT_TIMESTAMP tidak didukung.

      • Tipe string (CHAR, VARCHAR).

Contoh: kolom yang dihasilkan dengan tipe VIRTUAL atau STORED

Contoh 1

Gunakan kolom yang dihasilkan untuk menghitung panjang hipotenusa segitiga siku-siku (panjang hipotenusa sama dengan akar kuadrat dari jumlah kuadrat dua sisi):

CREATE TABLE triangle (
  sidea DOUBLE,
  sideb DOUBLE,
  sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb))
);
INSERT INTO triangle (sidea, sideb) VALUES(1,1),(3,4),(6,8);

Masukkan data ke tabel hive_hbase_table:

INSERT INTO triangle (sidea, sideb) VALUES(1,1),(3,4),(6,8);
select * from triangle;
+-------+-------+--------------------+
| sidea | sideb | sidec              |
+-------+-------+--------------------+
|   1.0 |   1.0 | 1.4142135623730951 |
|   3.0 |   4.0 |                5.0 |
|   6.0 |   8.0 |               10.0 |
+-------+-------+--------------------+

Contoh 2

Buat tabel partisi t1 yang berisi kolom yang dihasilkan b:

CREATE TABLE `t1` (
	`a` int(11) NOT NULL,
	`b` int(11) GENERATED ALWAYS AS (`a` + 1),
	PRIMARY KEY (`a`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4  dbpartition by hash(`a`)

Masukkan data ke tabel hive_hbase_table:

INSERT INTO t1(a) VALUES (1);
SELECT * FROM t1;
+---+---+
| a | b |
+---+---+
| 1 | 2 |
+---+---+

Contoh: kolom yang dihasilkan dengan tipe LOGICAL

Kolom dengan tipe LOGICAL dapat digunakan sebagai kunci partisi untuk strategi partisi yang lebih fleksibel. Anda juga dapat merujuk fungsi yang ditentukan pengguna dalam kolom LOGICAL.

Contoh 1: Pilih dua karakter terakhir dari bidang string sebagai kunci partisi.

CREATE TABLE `t2` (
	`a` int(11) NOT NULL,
	`b` varchar(32) DEFAULT NULL,
	`c` varchar(2) GENERATED ALWAYS AS (SUBSTR(`b`, -2)) LOGICAL,
	PRIMARY KEY (`a`),
	KEY `auto_shard_key_c` USING BTREE (`c`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4  dbpartition by hash(`c`)

Contoh 2: Buat kolom LOGICAL yang merujuk fungsi yang ditentukan pengguna.

Buat fungsi yang ditentukan pengguna my_abs:

DELIMITER &&
CREATE FUNCTION my_abs (
	a INT
)
RETURNS INT
BEGIN
	IF a < 0 THEN
		RETURN -a;
	ELSE
		RETURN a;
	END IF;
END&&
DELIMITER ;

Buat tabel t3 yang berisi kolom yang dihasilkan b. Ekspresi kolom tersebut mengandung fungsi my_abs:

CREATE TABLE `t3` (
	`a` int(11) NOT NULL,
	`b` int(11) GENERATED ALWAYS AS (MY_ABS(`a`)) LOGICAL,
	PRIMARY KEY (`a`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4  dbpartition by hash(`b`);

INSERT INTO t3 (a) VALUES(1),(-1);

EXPLAIN SELECT * FROM t3 WHERE b = 1;
+-----------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                     |
+-----------------------------------------------------------------------------------------------------------+
| LogicalView(tables="TEST_000002_GROUP.t3_WHHZ", sql="SELECT `a`, `b` FROM `t3` AS `t3` WHERE (`b` = ?)")  |
+-----------------------------------------------------------------------------------------------------------+

SELECT * FROM t3 WHERE b = 1;
+----+------+
| a  | b    |
+----+------+
| -1 |    1 |
|  1 |    1 |
+----+------+

Buat indeks pada kolom yang dihasilkan

PolarDB-X mendukung pembuatan indeks pada kolom yang dihasilkan.

Pertimbangan

  • Fitur ini hanya didukung oleh instance PolarDB-X Enterprise Edition V5.4.17 atau yang lebih baru.

  • Anda dapat membuat indeks lokal pada semua jenis kolom yang dihasilkan.

  • Anda dapat membuat indeks global pada kolom dengan tipe LOGICAL.

  • Anda tidak dapat membuat indeks global pada kolom dengan tipe VIRTUAL dan STORED.

Contoh

Contoh 1: Buat indeks lokal pada kolom dengan tipe VIRTUAL atau STORED.

CREATE TABLE t4 (
    a BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    c JSON,
    g INT AS (c->"$.id") VIRTUAL
) DBPARTITION BY HASH(a);

CREATE INDEX `i` ON `t4`(`g`);

INSERT INTO t4 (c) VALUES
  ('{"id": "1", "name": "Fred"}'),
  ('{"id": "2", "name": "Wilma"}'),
  ('{"id": "3", "name": "Barney"}'),
  ('{"id": "4", "name": "Betty"}');

EXPLAIN EXECUTE SELECT c->>"$.name" AS name FROM t4 WHERE g > 2;
+------+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| id   | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+------+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| 1    | SIMPLE      | t4    | NULL       | range | i             | i    | 5       | NULL | 1    | 100      | Using where |
+------+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+

Contoh 2: Buat indeks lokal pada kolom dengan tipe LOGICAL.

CREATE TABLE t5 (
    a BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    c varchar(32),
    g char(2) AS (substr(`c`, 2)) LOGICAL
) DBPARTITION BY HASH(a);

CREATE INDEX `i` ON `t5`(`g`);

INSERT INTO t5 (c) VALUES
  ('1111'),
  ('1112'),
  ('1211'),
  ('1311');

EXPLAIN EXECUTE SELECT c AS name FROM t5 WHERE g = '11';
+------+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------+
| id   | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                    |
+------+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------+
| 1    | SIMPLE      | t5    | NULL       | ref  | i             | i    | 8       | NULL | 4    | 100.00   | Using XPlan, Using where |
+------+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------+

Contoh 3: Buat indeks global pada kolom dengan tipe LOGICAL.

CREATE TABLE t6 (
    a BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    c varchar(32),
    g char(2) AS (substr(`c`, 2)) LOGICAL
) DBPARTITION BY HASH(a);

CREATE GLOBAL INDEX `g_i` ON `t6`(`g`) COVERING(`c`) DBPARTITION BY HASH(`g`);

INSERT INTO t6 (c) VALUES
  ('1111'),
  ('1112'),
  ('1211'),
  ('1311');

EXPLAIN SELECT c AS name FROM t6 WHERE g = '11';
+---------------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                               |
+---------------------------------------------------------------------------------------------------------------------+
| IndexScan(tables="TEST_DRDS_000000_GROUP.g_i_J1MT", sql="SELECT `c` AS `name` FROM `g_i` AS `g_i` WHERE (`g` = ?)") |
+---------------------------------------------------------------------------------------------------------------------+

Indeks Ekspresi

Saat PolarDB-X membuat indeks, jika entri indeks adalah ekspresi bukan kolom, PolarDB-X secara otomatis mengonversi ekspresi menjadi kolom yang dihasilkan dengan tipe VIRTUAL dan menambahkannya ke tabel. Setelah semua entri diproses, PolarDB-X melanjutkan untuk membuat indeks sesuai definisi Anda. Ekspresi dalam definisi indeks diganti dengan kolom yang dihasilkan yang sesuai.

Pertimbangan

  • Fitur ini hanya didukung oleh instance PolarDB-X Enterprise Edition V5.4.17 atau yang lebih baru.

  • Secara default, fitur indeks ekspresi dinonaktifkan. Anda dapat mengaktifkannya dengan menghidupkan saklar ENABLE_CREATE_EXPRESSION_INDEX.

    SET GLOBAL ENABLE_CREATE_EXPRESSION_INDEX=TRUE;
  • Indeks global tidak didukung.

  • Indeks unik tidak didukung.

  • Anda tidak dapat membuat indeks ekspresi saat membuat tabel. Setelah tabel dibuat, gunakan pernyataan ALTER TABLE atau CREATE INDEX untuk membuat indeks ekspresi.

  • Secara default, jika Anda menggunakan pernyataan DROP INDEX untuk menghapus indeks ekspresi, kolom yang dihasilkan yang dibuat secara otomatis tidak dihapus. Anda harus menggunakan pernyataan ALTER TABLE dalam mode DRDS atau AUTO untuk menghapus kolom tersebut. Untuk informasi lebih lanjut, lihat operasi ALTER TABLE (mode DRDS) atau ALTER TABLE (mode AUTO).

Contoh

Contoh 1: Buat indeks ekspresi.

  1. Buat tabel t7.

    CREATE TABLE t7 (
        a BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        c varchar(32)
    ) DBPARTITION BY HASH(a);
  2. Buat indeks ekspresi i.

    CREATE INDEX `i` ON `t7`(substr(`c`, 2));
  3. Setelah indeks ekspresi dibuat, tabel memiliki struktur berikut:

    CREATE TABLE `t7` (
    	`a` bigint(20) NOT NULL AUTO_INCREMENT BY GROUP,
    	`c` varchar(32) DEFAULT NULL,
    	`i$0` varchar(32) GENERATED ALWAYS AS (substr(`c`, 2)) VIRTUAL,
    	PRIMARY KEY (`a`),
    	KEY `i` (`i$0`)
    ) ENGINE = InnoDB dbpartition by hash(`a`)

Karena entri indeks dari indeks i adalah ekspresi, kolom yang dihasilkan i$0 ditambahkan ke tabel. Ekspresi kolom ini sama dengan ekspresi entri indeks. Setelah itu, indeks i dibuat dengan entri indeks diganti oleh kolom yang dihasilkan yang sesuai.

Setelah indeks ekspresi dibuat, performa pernyataan SQL berikut meningkat:

EXPLAIN EXECUTE SELECT * FROM t7 WHERE substr(`c`, 2) = '11';
+------+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id   | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+------+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1    | SIMPLE      | t7    | NULL       | ref  | i             | i    | 131     | const | 1    | 100      | NULL  |
+------+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+

Eksekusi pernyataan EXPLAIN EXECUTE untuk mendapatkan rencana eksekusi pada node data. Hasilnya menunjukkan bahwa indeks i dipilih:

EXPLAIN EXECUTE SELECT * FROM t7 WHERE substr(`c`, 2) = '11';
+------+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id   | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+------+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1    | SIMPLE      | t7    | NULL       | ref  | i             | i    | 131     | const | 1    | 100      | NULL  |
+------+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+

Contoh 2: Gunakan beberapa ekspresi dalam indeks.

Buat tabel t8:

CREATE INDEX idx ON t8(
  a + 1, 
  b, 
  SUBSTR(c, 2)
);

Setelah indeks ekspresi dibuat, tabel memiliki struktur berikut:

CREATE TABLE `t8` (
	`a` int(11) NOT NULL,
	`b` int(11) DEFAULT NULL,
	`c` varchar(32) DEFAULT NULL,
	`idx$0` bigint(20) GENERATED ALWAYS AS (`a` + 1) VIRTUAL,
	`idx$2` varchar(32) GENERATED ALWAYS AS (substr(`c`, 2)) VIRTUAL,
	PRIMARY KEY (`a`),
	KEY `idx` (`idx$0`, `b`, `idx$2`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4  dbpartition by hash(`a`)

Untuk indeks idx, entri indeks pertama dan ketiga adalah ekspresi. Oleh karena itu, dua kolom yang dihasilkan idx$0 dan idx$2 ditambahkan ke tabel. Ekspresi kedua kolom ini sama dengan ekspresi entri indeks pertama dan ketiga. Setelah itu, indeks idx dibuat dengan entri indeks pertama dan ketiga diganti oleh kolom yang dihasilkan yang sesuai.

Setelah indeks ekspresi dibuat, performa pernyataan SQL berikut meningkat:

SELECT * FROM t8 WHERE a+1=10 AND b=20 AND SUBSTR(c,2)='ab';

Eksekusi pernyataan EXPLAIN EXECUTE untuk mendapatkan rencana eksekusi pada node data. Hasilnya menunjukkan bahwa indeks idx dipilih:

EXPLAIN EXECUTE SELECT * FROM t4 WHERE a+1=10 AND b=20 AND SUBSTR(c,2)='ab';
+------+-------------+-------+------------+------+---------------+------+---------+-------------------+------+----------+-------+
| id   | select_type | table | partitions | type | possible_keys | key  | key_len | ref               | rows | filtered | Extra |
+------+-------------+-------+------------+------+---------------+------+---------+-------------------+------+----------+-------+
| 1    | SIMPLE      | t8    | NULL       | ref  | idx           | idx  | 145     | const,const,const | 1    | 100      | NULL  |
+------+-------------+-------+------------+------+---------------+------+---------+-------------------+------+----------+-------+