日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

生成列是一種特殊的列,其值是表達式計算的結果。本文介紹了生成列的創建方法,以及在生成列上創建索引的方法。

創建生成列

語法

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

生成列有以下三種類型:

  • VITRUAL:生成列的值不存儲,每次讀取該列時由存儲節點DN計算,不占用存儲空間。

    說明

    如果不指定關鍵字,默認創建VITRUAL類型的生成列。

  • STORED:生成列的值在數據行插入或更新時由存儲節點DN計算,并將結果儲存下來,需要占用存儲空間。

  • LOGICAL:與STORED類型相似,生成列的值在數據行插入或更新時計算,區別是生成列的值在計算節點CN計算,隨后以普通列的形式存儲到DN中。該類型的生成列可以作為分區鍵使用。

注意事項

5.4.17及以上版本的企業版實例支持此功能。

MySQL類似,相比普通列,使用生成列有如下限制條件:

  • 與MySQL相同的限制

    • 不支持為生成列指定默認值。

    • 不支持為生成列設置AUTO_INCREMENT屬性,或引用包含AUTO_INCREMENT屬性的列。

    • 不支持在生成列表達式中使用非確定性(deterministic)函數,例如UUID()、CONNECTION_ID()、NOW()等。

    • 不支持在生成列表達式中使用變量。

    • 不支持在生成列表達式中使用子查詢。

    • 不支持在INSERT/UPDATE語句中顯式指定生成列的值,生成列值的計算只能由數據庫自動完成。

  • 與MySQL不同的限制

    • 不支持在開啟冷數據歸檔功能的表中添加生成列。

    • 不支持VIRTUAL/STORED類型的生成列作為分區鍵、主鍵或者唯一鍵。

    • 不支持在VIRTUAL/STORED類型的生成列中引用存儲函數。

    • 如果一個全局二級索引中包含了VIRTUAL/STORED類型的生成列,那么該全局二級索引也需要包含生成列表達式中引用的所有列。

    • 不支持在LOGICAL類型的生成列表達式中引用VIRTUAL/STORED類型的生成列。

    • 不支持修改LOGICAL類型的生成列的類型,以及生成列的表達式中引用列的類型。

    • 僅支持以下類型作為LOGICAL類型的生成列和其表達式中引用的列的類型:

      • 整數類型(BIGINT、INT、MEDUMINT、SMALLINT、TINYINT);

      • 日期類型(DATETIME、DATE、TIMESTAMP),不支持包含ON UPDATE CURRENT_TIMESTAMP屬性的日期類型列;

      • 字符串類型(CHAR、VARCHAR)。

示例——VIRTUAL/STORED類型生成列

示例1

使用生成列自動計算直角三角形的斜邊(斜邊等于兩個直角邊平方和的平方根):

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);

插入數據:

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 |
+-------+-------+--------------------+

示例2

創建分區表t1,其中含有生成列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`)

插入數據:

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

示例——LOGICAL類型生成列示例

LOGICAL類型的生成列可以作為分區鍵使用,可以利用生成列實現更加靈活的分區策略。此外 LOGICAL 類型的生成列也支持引用自定義函數

示例1:選取字符串字段的最后兩個字符作為分區鍵。

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`)

示例2:引用自定義函數的LOGICAL類型的生成列。

創建自定義函數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 ;

創建表t3,該表中b列是一個生成列,表達式中含有自定義函數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 |
+----+------+

在生成列上創建索引

PolarDB-X支持在生成列上創建索引

注意事項

  • 5.4.17及以上版本的企業版實例支持此功能。

  • 支持在所有類型的生成列上創建局部索引。

  • 支持在LOGICAL類型的生成列上創建全局索引。

  • 不支持在VIRTUAL/STORED類型的生成列上創建全局索引。

示例

示例1:在VIRTUAL/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 |
+------+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+

示例2:在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 |
+------+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------+

示例3:在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` = ?)") |
+---------------------------------------------------------------------------------------------------------------------+

表達式索引

創建索引時,如果PolarDB-X發現某個索引項不是表中的一個列,而是一個表達式,此時PolarDB-X會自動將該表達式轉換為VIRTUAL類型的生成列并添加到表中。所有索引項處理完成后,PolarDB-X會按照用戶定義繼續創建索引,索引定義中的表達式索引項將被替換成對應的生成列。

注意事項

  • 5.4.17及以上版本的企業版實例支持此功能。

  • 創建表達式索引的功能默認關閉,需要打開ENABLE_CREATE_EXPRESSION_INDEX開關后才能使用。

    SET GLOBAL ENABLE_CREATE_EXPRESSION_INDEX=TRUE;
  • 不支持全局索引。

  • 不支持創建唯一索引。

  • 不支持在創建表語句中創建表達式索引,需要建表后通過ALTER TABLE或者CREATE INDEX語句添加表達式索引。

  • 使用DROP INDEX刪除表達式索引時,默認不會刪除創建表達式索引時自動創建的生成列,需要通過ALTER TABLE(DRDS模式)/ALTER TABLE(AUTO模式)手動刪除。

示例

示例1:創建一個表達式索引。

  1. 創建表t7。

    CREATE TABLE t7 (
        a BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        c varchar(32)
    ) DBPARTITION BY HASH(a);
  2. 創建表達式索引i。

    CREATE INDEX `i` ON `t7`(substr(`c`, 2));
  3. 完成表達式索引創建之后的表結構如下:

    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`)

由于索引i的索引項是表達式,因此在表中添加了一個生成列i$0,這個生成列的表達式就索引項的表達式。最后創建索引i,其中索引項被替換成為對應的生成列。

創建完表達式索引之后,以下SQL就可以利用表達式索引加快查詢速度:

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  |
+------+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+

執行EXPLAIN EXECUTE命令獲取在DN上的執行計劃,可以發現確實選擇了索引i:

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  |
+------+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+

示例2:在索引中使用多個表達式。

創建表t8:

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

完成表達式索引創建之后的表結構:

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`)

對于索引idx,第一個和第三個索引項是表達式,因此在表中添加了兩個生成列idx$0和idx$2,這兩個生成列的表達式就是第一個和第三個索引項的表達式。最后創建索引idx,其中第一個和第三個索引項被替換成為對應的生成列。

創建完表達式索引之后,以下SQL就可以利用表達式索引加快查詢速度:

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

使用EXPLAIN EXECUTE獲取在DN上的執行計劃,可以發現確實選擇了索引idx:

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  |
+------+-------------+-------+------------+------+---------------+------+---------+-------------------+------+----------+-------+