集合类型
SET数据类型是一种常量字符串类型数据,该类型只在建表时可以创建,适用于存储确定集合的子集的场景,这些字符串常量必须是SET定义时指定的常量字符串集合的子集。
SET创建语法如下:
SET('val1','val2',...) [CHARACTER SET charset_name] [COLLATE collation_name]
SET类型底层存储是以bitmap的形式存储,每个集合成员对应于一个比特位。每个集合的子集有字符串形式和整型两种表示方法,在操作时含义相同,以SET('beijing', 'shanghai', 'nanjing', 'wuhan') 为例,集合的字符串值和整型值对应的关系如表1所示。
|
集合字符串值 |
集合对应二进制值 |
整型值 |
|---|---|---|
|
'beijing' |
0001 |
1 |
|
'shanghai' |
0010 |
2 |
|
'nanjing' |
0100 |
4 |
|
'wuhan' |
1000 |
8 |
|
'beijing,nanjing' |
0101 |
5 |
M-Compatibility支持的SET类型如表2所示。
|
名称 |
描述 |
存储空间 |
|---|---|---|
|
SET |
集合类型,用于存储确定集合的子集的场景。
|
4字节~8字节 |
- SET数据类型的输入合法校验受sql_mode影响。宽松模式下,SET类型列输入不合法的值,会插入0值,即空串,严格模式下,插入不合法的值,会报错。
- SET数据类型创建时的每个成员值需要唯一。出现重复成员值,严格模式下报错,宽松模式下支持创建,但默认使用重复值中第一个出现的。
- SET数据类型支持字符集与字符序特性,且校验成员值是否重复与SET列上的字符序特性有关。
- SET数据类型不支持作为分区键。
- SET数据类型上的索引仅支持通过整型查找,使用字符串值无法走索引。
- 当前SET类型与其它类型比较不支持走索引扫描,需要在SET类型的列上,根据需要查询的数据类型,创建函数表达式索引来支持走索引扫描。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
-- 创建表和SET数据类型 m_db=# CREATE TABLE test_set(c1 SET('abc','efg','中文','汉字')); CREATE TABLE -- 查看表结构 m_db=# SELECT pg_get_tabledef('test_set'); pg_get_tabledef ------------------------------------------------------------------------------------------ SET search_path = public; + CREATE TABLE test_set ( + c1 SET('abc', 'efg', '中文', '汉字') CHARACTER SET `UTF8` COLLATE utf8mb4_general_ci+ ) + CHARACTER SET = "UTF8" COLLATE = "utf8mb4_general_ci" + WITH (orientation=row, compression=no, storage_type=USTORE, segment=off); (1 row) -- 插入字符串数据 m_db=# INSERT INTO test_set VALUES('abc,efg'),('efg,汉字,中文'), ('abc'); INSERT 0 3 -- 插入整型数据 m_db=# INSERT INTO test_set VALUES(5),(12); INSERT 0 2 -- 查询数据 m_db=# SELECT * FROM test_set; c1 --------------- abc,efg efg,中文,汉字 abc abc,中文 中文,汉字 (5 rows) -- 字符串形式查询数据 m_db=# SELECT * FROM test_set WHERE c1 = 'abc,efg'; c1 --------- abc,efg (1 row) -- 整型值形式查询数据 m_db=# SELECT * FROM test_set WHERE c1 = 12; c1 ----------- 中文,汉字 (1 row) -- 删除表 m_db=# DROP TABLE test_set; DROP TABLE -- 创建表和SET数据类型 m_db=# CREATE TABLE t1(id int, c1 set('a','bb','ccc')); CREATE TABLE -- 直接创建SET类型的索引无法支持走索引扫描 m_db=# CREATE INDEX idx_1 ON t1(c1); CREATE INDEX m_db=# EXPLAIN SELECT c1 FROM t1 WHERE c1 = 'a'; QUERY PLAN ----------------------------------------------------- Seq Scan on t1 (cost=0.00..59.00 rows=15 width=32) Filter: (cast_to_cstring(c1) = 'a'::text) (2 rows) -- 字符串查询,创建cast_to_cstring 函数索引,支持索引扫描 m_db=# CREATE INDEX id_t1 ON t1((cast_to_cstring(c1))); CREATE INDEX m_db=# EXPLAIN SELECT c1 FROM t1 WHERE c1 = 'a'; QUERY PLAN -------------------------------------------------------------------- Bitmap Heap Scan on t1 (cost=4.30..13.78 rows=6 width=32) Recheck Cond: (cast_to_cstring(c1) = 'a'::text) -> Bitmap Index Scan on id_t1 (cost=0.00..4.30 rows=6 width=0) Index Cond: (cast_to_cstring(c1) = 'a'::text) (4 rows) -- 整型查询,创建cast_to_int8函数索引,支持索引扫描 m_db=# CREATE INDEX id_t2 ON t1((cast_to_int8(c1))); CREATE INDEX m_db=# EXPLAIN SELECT c1 FROM t1 WHERE c1 = 5; QUERY PLAN -------------------------------------------------------------------- Bitmap Heap Scan on t1 (cost=4.30..13.78 rows=6 width=32) Recheck Cond: (cast_to_int8(c1) = 5) -> Bitmap Index Scan on id_t2 (cost=0.00..4.30 rows=6 width=0) Index Cond: (cast_to_int8(c1) = 5) (4 rows) |