Hologres SQL

1.SQL基础

1.1 DDL

创建数据库

CREATE DATABASE db_name [[WITH] OWNER [=] user_name];
  • 创建者自动成为新DB的owner
  • 用户需要有CREATEDB权限(或者superuser)

删除数据库

DROP DATABASE [IF EXISTS] db_name;
  • 只有该数据库的superuser或者该db的owner才能删除该数据库
  • 删除数据库会移除其中包括的所有对象
  • 不能在与目标数据库连接时执行DROP命令,但可以来连接到其他任意数据库

创建数据表

CREATE TABLE [IF EXISTS]
[schema_name.]table_name
([{column_name column_type [column_constraints, [...]]
    | table_contraints
    [, ...]
}]);
  • 在创建表时,如果不存在同名表且语义正确,表创建都会返回成功
  • 如果存在同名表:如果比指定IF NOT EXISTS选项,则返回异常;如果指定IF NOT EXISTS 选项,Holo会打印提示信息,跳过表创建步骤,返回成功

删除表

DROP TABLE [IF EXISTS] table_name [, ...];
  • DROP TABLE支持一次DROP多个表
  • 如果指定IF EXISTS,无论表存在与否,都会返回成功
  • 如果不指定IF EXISTS 选项而表不存在,则返回异常:ERROR:table “xxx” does not exist.

修改表
仅支持重命名表(RENAME TABLE)和增加列(ADD CPLUMN)。对于外部表(foreign table)没有限制

-- 重命名表
ALTER TABLE table_name RENAME to new_table_name;

-- 增加列
ALTER TABLE IF EXISTS table_name ADD COLUMN new_column_name data_type;

增加注释
Holo支持给表,外表,列等增加注释的功能

-- 给表增加注释
COMMENT ON TABLE table_name IS 'my comments on table table_name';

-- 给列增加注释
COMMENT ON COLUMN table_name.col1 IS 'This my first col1';

-- 给外部表增加注释
COMMENT ON FOREIGN TABLE foreign_table IS 'comment on my foreign table';

模式(SCHEMA)

  • 一个数据库可以包含多个schema
  • 多个用户使用一个数据库不会互相干扰,也便于管理
  • 每个DB有一个默认的public schema
  • Holo支持create schema、alter schema rename 暂时不支持drop schema
-- 查看当前schema
SELECT current_schema();

-- 创建新的schema
CREATE SCHEMA my_schema;

-- 跨schema建表
CREATE TABLE my_schema.mytest (name text, id int, age int);

-- 原schema下的表将全部转到新schema下
ALTER SCHEMA oldschema rename to newschema;

分区表
PostgreSQL分区表用于将一张大表分成同构的若干张子表,利于加速查询、方便管理

-- 创建分区表
CREATE TABLE [IF NOT EXISTS] [schema_name.]table_name PARTITION OF parent_table FOR VALUES IN (string_literal);

-- 分离目标表的指定分区
ALTER TABLE [IF EXISTS] table_name DETACH PARTITION partition_name;

-- 删除分区表
DROP TABLE table_name;

外部表
指不存储于Hologres中的表。Hologres与大数据生态无缝打通,可对外部表直接加速查询,也可以将外部表的数据导入到Hologres中进行数据处理
目前Holo只支持MaxCompute中的表作为外部表

-- 新建外部表
CREATE FOREIGN TABLE src_pt_odps(key text)
server odps_server options(project_name 'odps_project', table_name 'test');

-- 删除外部表
DROP FOREIGN TABLE [IF EXISTS] table_name [, ...]
[ CASCADE | RESTRICT];

-- 查看外部表
SELECT * FROM table_name;

** CREATE CAST 用于定义数据类型之间的转换**

CREATE CAST(source_type AS target_type)
    WITH INOUT
    [ AS ASSIGNMENT | AS IMPLICIT]
    
注:
source_type:该转换的源数据类型
targer_type:该转换的目标数据类型

示例:创建数据类型之间的转换

CREATE CAST (text AS integer) WITH INOUT AS IMPLICIT;

** DROP CAST语句用于删除已定义的数据类型转换

DROP CAST [IF EXISTS] (source_type AS targer_type)

示例:
DROP CAST IF EXISTS (text AS timestamptz);
DROP CAST IF EXISTS (text AS integer);

创建视图

CREATE [TEMP | TEMPORARY] VIEW
view_name AS
SELECT column1, column2 ...
FROM table_name
WHERE [condition];

-- 创建内部表视图
create view view1 as select * from t1_foreign;

-- 创建内部表及外部表的联合视图
create view view2 as select * from t2_holo 
union all
select * from t1_foreign;

删除视图

DROP VIEW ;

1.2 DML

插入

INSERT INTO table[(column [,...])] VALUES ({expression} [,...]) [, ...] | query

在Hologres中,INSERT支持两种形式
1.插入确定的value
INSERT INTO rh_holo2 (cate_id, cate_name) VALUES
(3, 't1'),
(3, 'f1'),
(3, 'trxxue'),
(3, 'x'),
(4, 'sajojsaio');

2.插入select的结果
INSERT INTO test2
SELECT * FROM test1;

DELETE:对表指定列的行数据进行删除

DELETE FROM table_name [*]
[ [AS] alias] [WHERE condition]

alias:别名,目标表的替代名称
condition:删除的条件

用法举例:
DELETE FROM delete_test AS dt WHERE dt.a = 10;
DELETE FROM delete_test AS dt WHERE dt.b is null;
DELETE FROM delete+test AS dt WHERE dt.b = "";

UPDATE:对表指定列的行数据进行更新

UPDATE table [*] [ [AS] alias]
SET column = {expression}
[ FROM from_list] [WHERE condition]

alias:别名,目标表的代称
expression:表达式
condition:更新条件

举例:
UPDATE update_test set b = b + 10 where a = 'b1';

UPDATE update_test set c = 'new_' || a, d = null
where b = 20;

UPDATE update_test set (b,c,d) = (1,"test_c","d");

SELECT查询语法

[WITH with_query [, ...]]
SELECT [ALL | DISTINCT [ ON (expression [, ...])]]
* | expression [[AS] output_name] [, ...]
[FROM from_item [, ...]]
[WHERE condition]
[GROUP BY grouping_element [, ...]]
[HAVING condition [, ...]]
[{UNION | INTERSECT | EXCEPT} [ALL] SELECT]
[ORDER BY expression [ASC | DESC | USING operator] [, ...]]
[LIMIT {count | ALL}]

DISTINCT:取出重复行,只保留一行
FROM:为SELECT指定一个或更多源表
WHERE:展示condition指定的内容
GROUP BY:按照指定的表达式分组
HAVING:过滤
UNION:SELECT语句所返回的行的并集
INTERSECT:select语句返回的行的交集
EXCEPT:计算位于左SELECT语句的结果中但不在右SELECT语句结果中的行集合
ORDER BY:按照指定的表达式排序
LIMIT:count指定要返回的最大行数


示例:
select * from sale_detail where shop_name like 'hang%';
从sale_detail表中查询所有带hang的店铺

select region from sale_detail group by region;
从sale_detail表中查询region信息并以region进行分组

select * from sale_detail order by region limit 100;
从sale_detail表中查询region信息并以region排序数据100行

UNION并集
求两个数据集的并集。即,将两个数据集合并成一个数据集

未去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
UNION ALL
SELECT * FROM VALUES (1, 2), (3, 4) t(a, b);

去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
UNION
SELECT * FROM VALUES (1, 2), (3, 4) t(a, b);

INTERSECT交集
求两个数据集的交集。即,数据两个数据集均包含的记录

未去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
INTERSECT ALL
SELECT * FROM VALUES (1, 2), (1, 2), (7, 8) t(a, b);

去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
INTERSECT
SELECT * FROM VALUES (1, 2), (1, 2), (7, 8) t(a, b);

EXCEPT补集
求第二个数据集在第一个数据集中的补集。即,输出第一个数据集包含而第二个数据集不包含的记录

未去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
EXCEPT ALL
SELECT * FROM VALUES (1, 2), (1, 2), (7, 8) t(a, b);

去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
EXCEPT
SELECT * FROM VALUES (1, 2), (1, 2), (7, 8) t(a, b);

INSERT ON CONFLICT语句用于在指定列插入某行数据时,如果主键存在重复的行数据,则对该数据执行更新或跳过操作
应用场景:适用于SQL方式导入数据的场景

create table conflict_2(
 a int not null primary key,
 b int,
 c int
);

insert into conflict_2 values(1,5,6);

insert into conflict_1 select * from conflict_2 on conflict(a) do update set b = excluded.b; //主键相同时,将表conflict_2的列数据更新到conflict_1中

insert into conflict_1 values(2,7,8) on conflict(a) do update set b = excluded.b, c = excluded,c
where conflict_1.c = 4; //主键值相同时,将表conflict_2的某一行数据全部插入至表conflict_1中

insert into conflict_1 select * from conflict_2 on conflict(a) do nothing; //主键相同时,跳过表conflict_2的数据

insert into conflict_1 select * from conflict_2 on conflict do nothing; //do nothing不指定冲突列时,默认冲突列为主键

TRUNCATE语句用于清空目标表
使用限制:

  • Hologres支持Sequence,但目前仅支持CONTINUE IDENTITY,不支持RESTART IDENTITY
  • Hologres支持对普通表、分区父表及分区子表执行TRUNCATE语句
  • Hologres不支持对外部表执行TRUNCATE语句
TRUNCATE [TABLE] name [, ...] [CONTINUE IDENTITY | RESTART IDENTITY]

# 默认为CONTINUE IDENTITY

2.SQL高阶

2.1 存储属性设置

  • Hologres目前通过set_table_property procedure来指定表的额外物理存储属性,合理设置table property对于查询的性能影响极大
  • set_table_property的调用需要与create table在同一事务中执行
  • set_table_property对于同一个key不能重复调用
call set_table_property('table_name', 'orientation', '[column | row]');
call set_table_property('table_name', 'clustering_key', '[columnName{: [desc | asc]} [, ...]]');
call set_table_property('table_name', 'segment_key', '[columnName [, ...]]');
call set_table_property('table_name', 'bitmap_columns', '[columnName [, ...]]');
call set_table_property('table_name', 'dictionary_encoding_columns', '[columnName [,...]]');
call set_table_property('table_name', 'time_to_live_in_seconds', '');
call set_table_property('table_name', 'distribution_key', '[columnName [, ...]]');

2.2 存储类型设置

  • Hologres目前支持按行存储和按列存储两种存储类型,通过orientation来指定
  • 按行存储对于高QPS的基于primary key的点查询性能较好,例如where pk = abc,其余场景应该选用按列存
# 按行存
begin;
create table tb1 (a int not null, b text not null, primary key(a));
call set_table_property("tb1", "orientation", "row");
commit;

# 按列存
begin;
create table tb1 (a int not null, b text not null, primary key(a));
call set_table_property("tb1", "orientation", "column");
commit;

2.3 聚簇键设置

  • clustering_key 指定一列作为聚簇索引,Hologres在指定的列上将建立聚簇索引。Hologres会在聚簇索引上对数据进行排序,建立聚簇索引能够加速用户在索引列上的range和filter查询
  • 数据类型为float/double的列,不能设置为clustering_key
  • 每个表只能有最多一个聚簇索引
begin;
create table tb1 (a int not null, b text not null);
call set_table_property('tb1', 'clustering_key', 'a');
commit;

2.4 分段键设置

  • segment_key指定一些列作为分段键,当查询条件包含分段列时,查询可以通过segment_key快速找到相应数据对应的存储位置,segment_key要求按照数据输入自增
  • 一般只有时间类型的字段(timestamptz)适合设置为segment_key,其他场景基本不需要设置
  • 只有列存表支持分段键
begin;
create table tb1 (a int not null, ts timestamp not null);
call set_table_property('tb1', 'segment_key', 'ts');
commit;

2.5 比特编码列设置

  • bitmap_columns指定比特编码列,Hologres在这些列上构建比特编码。bitmap可以对segment内部的数据进行快速过滤,所以建议用户把filter条件的数据建成比特编码
  • 默认所有text列都会被隐式地设置到bitmap_columns中
  • 只有列存表支持比特编码列
begin;
create table tb1 (a int not null, b text not null);
call set_table_property('tb1', 'bitmap_columns', 'a');
commit;

2.6 字典编码列设置

  • dictionary_encoding_columns指定字典编码列,Hologres为指定列的值构建字典映射,字典编码可以将字符串的比较转成数字的比较,加速group by查询,建议用户将group by的字段都建成dictionary_encoding_columns
  • 默认所有text列都会被隐式地设置到dictionary_encoding_columns中
  • 不建议将基数高的列建为dictionary_encoding_columns,会导致查询性能变差
  • 只有列存表支持字典编码列
begin;
create table tb1 (a int not null, b text not null);
call set_table_property('tb1', 'dictionary_encoding_columns', 'b');
commit;

2.7 分布键设置

  • Hologres中,数据库表默认为随机分布形式。数据将被随机分配到各个shard上,如果用户制定了分布列,数据将按照指定列,将数据shuffle到各个shard,同样的数据肯定会在同样的shard中,当用户以分布列左过滤条件时,Hologres可以直接筛选出数据相关的shard进行扫描。当用户以分布列做join条件时,Hologres不需要再次将数据shuffle到其他计算节点,直接在本节点join数据即可,可大大提高执行效率。同时如果用户group by的key的时分布列也可以减少一次数据shuffle
  • 有pk的数表,默认时pk,可以指定pk字段的子集,不能随意指定
  • 用户可以用过shard_count来指定表的shard数,如果不指定每个数据库都有一个默认的shard数。一旦用户指定了一个表的shard数,其他的表如果想要和这个表做local join必须指定colcate with这个表
begin;
create table tb1 (a int, b int, c int);
call set_table_property('tb1', 'distribution_key', 'a');
commit;

begin;
create table tb2 (a int, b int, c int);
call set_table_property('tb1', 'distribution_key', 'b');
commit;

select count(1) from tb1 join tb2 on tb1.a = tb2.b;  -- 将分布列设置为join key

2.8 数据生命周期管理

  • time_to_live_in_seconds 指定了表数据的生存时间,单位为秒,必须非负数字类型
  • 表数据的TTL并不是精确的时间,当超过设置的TTL后,系统会在某一个时间自动删除表数据,所以业务逻辑不能强依赖TTL
begin;
create table tb1 (a int not null, b text not null);
call set_table_property('tb1', 'time_to_live_in_seconds', '3.1415926');
commit;

2.9 性能调优

用过explain查看执行计划
执行analyze,生成统计信息

你可能感兴趣的:(holo,sql)