第 20章 定义数据库对象
本节涵盖了Greenplum的数据库以及如何创建和管理数据库对象的数据定义语言(DDL)。
在Greenplum数据库中创建对象包括一些前期选择例如数据分布,存储选项,数据加载及其他Greenplum数据库特性,这些特性会影响到数据库的性能。了解这些选项,以及如何使用会帮助你做出正确的选择。大部分Greenplum的先进特定都在SQL CREATE DDL语句中扩展使用。
一个Greenplum的数据库系统是Greenplum数据引擎的单个实例。可以有安装了几个独立的Greenplum数据库系统,但通常只有一个是由环境变量设置中选择。请参阅您的Greenplum管理员了解详情。
There can bemultiple databases in a Greenplum Database system. This is different from somedatabase management systems (such as Oracle) where the database instance is the database.Although you can create many databases in a Greenplum system, client programscan connect to and access only one database at a time — you cannot cross-querybetween databases.
Greenplum数据系统中可以有多个数据库。这是和一些数据库管理系统(如Oracle),数据库实例就是数据库是不同的。虽然你可以在一个GPEB中创建多个数据库,客户端程序可以同时连接到并访问其中一个数据库- 你不能在数据库之间进行交叉查询。
创建和管理数据库
About TemplateDatabases
GreenplumDatabase uses two other database templates, templateO and postgres, internally.Do not drop or modify templateOor postgres.You can use templ^teOto create a completely clean database containing only the standard objectspredefined by Greenplum Database at initialization, especially if you modified templatel.
每个新的数据库都是基于一个模板创建的。GPDB提供了一个默认数据库template。在第一次连接到GPDB时是用的template。GPDB在创建数据库时默认都是使用template1除非你指定另外一个模板。不要在template中创建任何对象,除非这个对象是在你要创建的每个数据库中都要使用的。
GPDB在内部使用了其他两个数据库模板,template0和postgres。不要删除或修改template0或postgres。你可以使用template0来创建一个完全干净的,只有GPDB预定义对象的数据库,特别是你修改了template1的情况下。
创建数据库
CREATE DATABASE命令创建一个新的数据库。例如:
=> CREATE DATABASE new_dbname;
要创建一个数据库,你必须有权创建数据库或成为Greenplum数据引擎超级用户。如果你没有正确的权限,则不能创建数据库。您Greenplum的数据库管理员联系要么给你必要的特权或为您创建一个数据库。
您还可以使用客户端程序CREATEDB创建数据库。例如,在一个命令行终端运行以下命令使用提供的主机名和端口连接到Greenplum数据,并创建一个数据库名为MYDa tabase:
$ CREATEDB-h MASTERHOST-p5432MyDatabase的
主机名和端口必须安装Greenplum的数据库系统的主机名和端口相匹配。
一些对象,例如角色,是通过在Greenplum数据系统的所有数据库共享。其他对象,如您创建表,已知仅在创建它们的数据库。
克隆数据库
默认情况下,一个新的数据库是由克隆的标准系统的数据库模板,templatel创建。任何数据库可以创建一个新数据库时,由此提供的能力“克隆”或复制现有的数据库和该数据库中的所有对象和数据被用作模板。例如:
=> CREATEDATABASE newdbname TEMPLATE old dbname;
查看数据库的列表
如果您在PSQL客户端程序时,您可以使用\l 元命令可显示你的Greenplum数据库系统的数据库和模板列表。如果使用其他客户端程序,如果你是一个超级用户,您可以从pg_database查询系统目录表的数据库列表。例如:
=>SELECT datname from pg_database;
改变数据库
ALTERDATABASE命令修改数据库属性,如所有者,名称或默认配置属性。例如,下面的命令更改设置的默认模式搜索路径(SEARCH_PATH配置参数)的数据库:
=> ALTERDATABASE mydatabase SET search_path TO myschema, public, pg_catalog;
要改变一个数据库,你必须是数据库或超级用户的所有者。
删除数据库
该DROP DATABASE命令删除(或删除)的数据库。它会删除系统目录条目的数据库,并删除在包含数据的磁盘上的数据库目录。您必须是数据库所有者或者超级用户删除数据库,而你或其他人连接到它,你不能删除的数据库。在删除数据库之前,连接到template1(或其他数据库)。例如:
=> \c template1
=> DROPDATABASE MyDatabase;
您还可以使用客户端程序DROPDB命令来删除数据库。例如,下面的命令使用提供的主机名和端口连接到Greenplum的数据库并删除数据库MyDatabase的:
$ DROPDB -hMASTERHOST -p 5432 MyDatabase;
警告:删除数据库无法复原。
创建和管理表空间
表空间允许数据库管理员在每台机器上使用多种文件系统并决定如何最好的使用物理存储来存储数据库对象。通过使用文件空间来将这些空间进行命名,使得用户可以在上面创建对象。表空间允许您为频繁和不经常使用的数据库对象分配不同的存储或者控制某些数据库对象的I / O性能。例如,放置常用在使用高性能的固态硬盘(SSD),以及其他地方对表标准硬盘的文件系统表。
表空间需要个文件系统位置来存放它的数据库文件。在GPDB中,master节点和段节点(主段和镜像段)都需要不同的存储位置。文件系统位置在Greenplum的系统中所有组件的集合是一个文件空间。文件空间可以存放一个或多个表。
创建文件空间
文件空间留出存储您的Greenplum系统。文件空间是映射到一组在Greenplum的主机的文件系统位置的一个象征性的存储标识符。要创建一个文件空间,准备在所有Greenplum的主机的逻辑文件系统,然后使用gpfilespace工具来定义文件空间。你必须是一个数据库超级用户创建文件空间。
注:Greenplum数据是不是在你的底层系统直接了解文件系统的边界。它在你告诉它使用的目录中存储的文件。你不能一个逻辑文件系统中的控制单个文件在磁盘上的位置。
To create afilespace using gpfilespace
1. Log in to theGreenplum Database master as the gpadmin user.
$ su - gpadmin
2. Create afilespace configuration file:
$ gpfilespace -ogpfilespace_config
3. 在提示符下,为文件空间,主段文件系统位置,镜子段文件系统位置,以及一个主文件系统位置输入一个名称。主服务器和镜像的位置请参考段上的主机目录;主位置指的是主服务器主机和备用主,如果配置了standbymaster。例如,如果你的配置有2个小学和每个主机的镜像段:
Enter aname for this filespace> fastdisk
primarylocation 1> /gpfs1/seg1
primarylocation 2> /gpfs1/seg2
mirrorlocation 1> /gpfs2/mir1
mirrorlocation 2> /gpfs2/mir2
master location> /gpfs1/master
4. gpfilespace 创建一个配置文件. 需要检查这个配置文件是否正确.
5. Rungpfilespace again to create the filespace based on the configuration file:
$ gpfilespace-c gpfilespace_config
移动临时目录或交易目录
你可以移动临时或交易文件目录到一个特定的文件空间以提升在查询时的性能,创建备份,使得数据存储更有条理化。
临时文件和事务文件的专用文件空间称为gp_temporary_files_filespace和gp_transaction_files_filespace两个独立的平面文件所跟踪记录。这些位于每个主服务器和镜像段pg_system目录,并在主服务器和standby。你必须是一个超级用户移动临时或交易文件。只有gpfilespace实用程序可以写入该文件。
有关临时文件和事务文件
除非另有规定,临时和事务文件与所有的用户数据一起存储。临时文件的默认位置,
还要注意有关临时或交易文件中的以下信息:
•您可以指定专门只有一个临时或交易文件的文件空间,虽然你可以使用相同的文件空间来存储其他类型的文件。
•如果使用的临时文件不能删除文件空间。
•您必须提前创建文件空间。请参阅创建文件空间。
要移动使用gpfilespace临时文件
1. .检查文件空间存在,并且是用于存储所有其他用户的数据文件空间不同。
2. 使用智能关机使得Greenplum数据库引擎脱机。如果有任何连接仍在执行中,则gpfilespace--movetempfiles实用程序将失败
3. 启动 GreenplumDatabase online并保持无活动会话,执行如下命令:
gpfilespace--movetempfilespace filespace_name
临时文件的位置被存储在段配置共享存储器(PMModuleState)和每当创建临时文件时,打开或丢弃。
使用gpfilespace移动事务文件
1、 检查文件空间存在,并且是用于存储所有其他用户的数据文件空间不同.
2、 使用智能关机使得Greenplum数据库引擎脱机。如果有任何连接仍在执行中。gpfilespace --movetransfiles实用程序将失败。
3、 启动 Greenplum Database online并保持无活动会话,执行如下命令:
gpfilespace--movetransfilespace filespace_name
创建表空间
创建文件空间后,使用CREATETABLESPACE命令来定义使用该文件空间的表空间。例如:
=# CREATETABLESPACE fastspace FILESPACE fastdisk;
数据库超级用户定义的表空间并授予访问数据库用户与GRANTCREATE命令。例如:
=# GRANT CREATEON TABLESPACE fastspace TO admin;
使用表空间存储数据库对象
对表空间有CREATE权限的用户可以创建该表空间数据库对象,如表,索引和数据库。该命令是:
CREATEtablename(选项) TABLESPACESPACENAME
例如,下面的命令在表空间spacel上创建表:
CREATETABLE foo(i int) TABLESPACE spacel;
您也可以使用default_tablespace参数指定默认表空间CREATE TABLE和CREATE没有指定表空间INDEX命令:
SETdefault_tablespace = spacel;
CREATETABLE foo(i int);
用数据库存储,通过服务器进程使用该数据库中创建数据库的系统目录,临时文件,并选择在数据库中创建表和索引的默认表空间,如果创建对象时没有指定表空间关联的表空间。如果您在创建数据库不指定表空间,数据库采用其模板数据库所使用的相同的表空间。
如果你有相应的权限,你可以使用一个表空间从任何数据库。
查看现有的表空间和文件空间
每个Greenplum数据系统具有以下默认表空间。
•pg_global共享系统目录。
•pg_default,默认表空间。由的template1和template0中的数据库中。
这些表空间使用系统默认的文件空间,pg_system,数据目录位置在创建
系统初始化。
要查看文件空间的信息,请查看pg_filespace和pg_filespace_entry目录表。你可以加入
这些表pg_tablespace看到一个表空间的完整定义。 例如:
=# SELECT spcname astblspc, fsname as filespc,
fsedbid as seg_dbid,fselocation as datadir
FROM pg_tablespace pgts,pg_filespace pgfs,
pg_filespace_entry pgfse
WHEREpgts.spcfsoid=pgfse.fsefsoid
ANDpgfse.fsefsoid=pgfs.oid
ORDERBY tblspc, seg_dbid;
删除表空间和文件空间
要删除表空间,您必须是表所有者或超级用户。直到使用表空间的所有数据库中的所有对象被删除,则不能删除表空间。
只有超级用户可以删除文件空间。直到使用该文件空间所有表被删除文件空间不能被删除。
该DROPTABLESPACE命令删除一个空的表空间。
该DROP FILESPACE命令删除一个空文件空间。
注意:如果临时存储或交易文件不能删除文件空间。
创建和管理模式
模式逻辑地组织在数据库中的对象和数据。模式让你有多个对象(如表)使用相同的名称在数据库中没有冲突,如果对象是在不同的模式。
The Default "Public" Schema
每个数据库有一个名为public默认架构。如果你没有创建任何模式,在public模式中创建对象。所有的数据库角色(用户)在public模式中创建和使用权限。当你创建一个架构,您权限授予您的用户允许访问的模式。
创建模式
使用CREATE SCHEMA命令来创建一个新的模式。例如:
=>CREATE SCHEMA MYSCHEMA;
要创建或在模式中访问对象,写出一个合格的名称,包括模式名和表
名用句点分隔。例如:
myschema.table
请参阅架构搜索路径有关访问架构信息。
您可以创建别人拥有的模式,例如,限制你的用户的活动
明确的命名空间。语法是:
=> CREATESCHEMA schemaname AUTHORIZATION username;
模式搜索路径
要在数据库中指定对象的位置,使用模式限定名称。例如:
=> SELECT* FROM myschema.mytable;
您可以设置SEARCH_PATH配置参数来指定要搜索可用的命令
架构的对象。在搜索路径中第一家上市的模式将成为默认的模式。如果模式
未指定,在默认模式中创建对象。
设置模式搜索路径
该SEARCH_PATH配置参数设置模式搜索顺序。 ALTER DATABASE命令
设置搜索路径。例如:
=> ALTERDATABASE mydatabase SET search_path TO myschema, public, pg_catalog;
You can alsoset search_path for a particular role (user) using the alter role command. 例如:
=> ALTERROLE sally SET search_path TO myschema, public, pg_catalog;
查看当前模式
使用CURRENT_SCHEMA()函数来查看当前的架构。例如:
=> SELECT current_schema();
使用show命令查看当前的搜索路径. 例如:
=> SHOWsearch_path;
删除模式
使用DROP SCHEMA命令删除(删除)的模式。例如:
=> DROPSCHEMA myschema;
默认情况下,该模式必须为空,然后才能删除它。要删除一个模式及其所有对象
(表,数据,函数,等等)的使用:
=> DROPSCHEMA myschema CASCADE;
系统模式
下面的系统级架构在每个数据库中存在:
• pg_catalog包含系统目录表,内置数据类型,函数和操作符。它始终是模式搜索路径的一部分,即使它不是在搜索路径明确命名。
• information_schema由一套标准化包含有关数据库中的对象的信息视图。这些观点得到一种标准化的方式在系统目录表系统信息。
• pg_toast 存储那些诸如超过页面大小的对象,这个模式仅在Greenplum数据库系统内部使用。
• pg_bitmapindex存储位图索引的对象,如值列表。该模式由Greenplum数据系统内部使用。
• pg_aoseg存储追加优化的表对象。该模式由Greenplum数据系统内部使用。
• gp_toolkit 包含外部表,视图和功能,您可以用SQL命令访问的管理模式。所有的数据库用户都可以访问gp_toolkit查看和查询系统的日志文件和其他系统指标。
创建和管理表
Greenplum数据表类似于在任何关系数据库表,除了表行中的系统在不同的区段分布。当你创建一个表,你指定表的分发策略。
创建表
CREATE TABLE命令创建一个表并定义其结构。当你创建一个表,你定义:
• 表及其相关的数据类型的列。请参见选择列. SeeChoosingColumn Data Types.
• 任何表或列约束,以限制列或表可以包含的数据. SeeSetting Table andColumn Constraints.
• 表的分发策略, 决定Greenplum数据在不同的段是如何分发的SeeChoosing the Table Distribution Policy.
• 表存储在磁盘上的方式. SeeChoosing the Table storage Model.
• 对于大表的表分区策略. See Creating and Managing Databases.
选择列的数据类型
列的数据类型决定了列可以包含的数据类型。选择使用尽可能少的空间,但仍然可容纳的数据,并且最好限制了数据的数据类型。例如,使用字符串类型类存储字符串,date 或 timestamp存储日期,数值类型来存储数字。
对于包含文本的列,Pivotal建议使用varchar 或 text,不推荐使用CHAR类型。在 GreenplumDatabase, varchar 或 text可以处理空白填充(空格字符添加的最后一个非空格字符后), char 类型不行. 有关字符数据类型的信息,请参阅Greenplum数据参考指南CREATE TABLE命令。
使用,将满足您的数字数据,并允许将来扩展最小的数字数据类型。例如,使用BIGINT存储那些适合于INT或SMALLINT的数据就会浪费存储空间。如果你的从一个较小的数据雷翔更改为一个较大的数据类型需要加载大量的数据,并且很耗时。如果你目前的数据值适合在SMALLINT,但它是可能的值将扩大,INT是更好的长期选择。
使用相同的数据类型,您打算在跨表连接到使用的列。交叉表通常联接使用一个表的主键和另一个表的外键。当数据类型是不同的,该数据库必须转换其中之一,使所述数据值可以被正确比较,这增加了不必要的开销。
Greenplum的数据库都有提供给用户丰富的原生数据类型。看到Greenplum数据参考指南,了解有关内置数据类型的信息。
设置表和列的约束
您可以在列和表定义约束你的表来限制数据。对Greenplum的数据库约束的支持是一样的PostgreSQL有一些限制,其中包括:
• CHECK约束只能引用它们所定义的表。
• UNIQUE和PRIMARY KEY约束必须是如果有的话,他们的表的分布键和分区键兼容
• 外键约束允许的,但不会强制执行。
•约束你的分区表定义适用于分区表作为一个整体。不能在表中的各个部分定义约束。
Check 约束
检查约束允许您指定在某列的值必须符合一个Boolean(调查真相价值)的表达。例如,需要正的产品价格:
=> CREATE TABLE products
(product_no integer, name text,
price numeric CHECK(price > 0));
Not-NullConstraints
非空约束指定一个列不能有空值。一个非空约束总是写成一个列约束。例如:
=> CREATE TABLE products
(product_no integer NOT NULL, name text NOT NULL, price numeric );
唯一约束
唯一约束确保包含在列中的数据或一组列相对于表中的所有行唯一的。该表必须散列分布(未随机分布),和约束列必须是相同的(或超集)的表的散列key列。例如: 约束列和散列key相同,或者约束列是散列key的超集。
=> CREATE TABLE products
(product_no integer UNIQUE, name text, price numeric)
DISTRIBUTED BY(product_no);
主键
主键约束是一个独特的约束和NOT NULL约束的组合。该表必须散列分布(未随机分布),和主键列必须是相同的(或超集)的表的分配密钥列。如果表的主键,该列(或组列)被选择作为用于由缺省表中的分配密钥。例如:
=> CREATE TABLE products
(product_no integer PRIMARY KEY, name text, pricenumeric)
DISTRIBUTED BY(product_no);
外键
外键不支持。你可以声明它们,但引用完整性不执行。
外键约束指定一列或一组列的值必须符合另一个表的一些行的值,以保持两个相关表之间的参照完整性。参照完整性检查不能在Greenplum的数据库的分布表段之间执行。
选择表的分布策略
所有Greenplum的数据库表均有分布。当您创建或变更表,你选择指定分发了(散列分布)或随机地(循环分布)分布来确定表行分配。
注:Greenplum的数据库服务器配置参数gp_create_table_random_default_distribution控制,如果当你创建一个表分布式BY子句中未指定表分配政策。
有关参数的信息,请参阅Greenplum数据参考指南“服务器配置参数
在制定表的分布策略时,需要考虑如下几点:
• 数据分布情况 —为了获得最佳性能,各方面应包含数据的等分。如果数据是不平衡或倾斜,具有更多的数据段必须更努力来执行其查询处理的一部分。选择一个分配密钥是对于每个记录,独特如主键。
• 本地和分布式操作 — 本地操作远快于分布式操作。在区段上,含有关联、排序、聚合等操作时本地操作的执行时最快的。在系统级所做的工作需要跨段分布的元组,这是低效率的。当表含有一个共同的分布键时,在它们共有的分布键上的关联或排序都是在本地执行。对于随机分布的表,执行关联查询是一个很差的选择。
• 查询处理—为了达到最佳性能,各个段应当承担查询工作负载的相等的份额。查询工作负载可能会出现偏差,如果一个表的数据分配政策和查询谓词没有得到很好的匹配。例如,假设一个销售交易表的客户编号列(分发密钥)分布。如果在查询谓词引用单个客户ID,查询处理工作集中在只有一个段。
声明分布键
CREATE TABLE可选择使用distributed by或distributedrandomly来指定分布策略。默认是使用或者主键(如果表中有一个)的散列分配政策或表的分布键的第一列。具有几何或用户定义的数据类型的列都没有资格成为表的分布键列。如果表中没有符合条件的栏,Greenplum的随机或循环方式分配的行。
为了确保即使数据的分布,选择分发关键是为每个记录是唯一的。如果这是不可能的,选择随机分布的。例如:
=> CREATE TABLE products
(name varchar(40), prod_idinteger, supplier_id integer)
DISTRIBUTED BY (prod_id);
=> CREATE TABLErandom_stuff
(things text, doodads text,etc text)
DISTRIBUTED RANDOMLY;
选择表的存储模式
Greenplum的数据库支持多种存储模式和存储模式的混合。当你创建一个表,你选择如何存储其数据。本主题介绍了表存储以及如何选择适合您的工作负载的最佳存储模型的选项。
• 堆存储
• 追加优化存储
• 选择行存储或列存储
• 使用压缩 (只能是追加优化表)
• 检查追加优化表的压缩和分布
• 更改表
• 删除表
注意:为了简化数据库表的创建,您可以与Greenplum的数据库服务器配置参数表的一些存储选项指定默认值gp_default_storage_options.
有关参数的信息,请参阅Greenplum数据参考指南“服务器配置参数”。
堆存储
默认情况下,Greenplum数据引擎使用和PostgreSQL相同的堆存储模型。堆表存储效果最佳OLTP类型的工作负荷,在堆表里最初加载后的数据经常被修改。 UPDATE和DELETE操作需要存储行级版本信息,以确保可靠的数据库事务处理。堆表是最适合较小的表,如维表,它们最初加载后经常更新。
追加优化存储
附加优化表存储是数据仓库环境中的非规范化事实表的最佳存储方式。反规范化事实表通常是系统中的最大的表。事实表通常是批量的加载和只读型的访问。将大的事实表存储为追加优化模式可以消除的每行更新的可见性信息的存储开销,每行节约大约20个字节。这允许一个更精简,更易于优化页面结构。附加优化表的存储模型批量数据加载优化。不建议单列INSERT语句。
创建一个堆表
行存储的表默认就是堆表存储。
=> CREATETABLE foo (a int, b text) DISTRIBUTED BY (a);
创建追加优化表
使用CREATETABLE命令的WITH子句申报表的存储选项。默认值是创建该表作为常规面向行的堆存储表。例如,创建具有无压缩追加优化表:
=> CREATETABLE bar (a int, b text)
WITH (appendonly=true)
DISTRIBUTED BY(a);
UPDATE和DELETE不会在串行化事务允许在附加优化表,并会导致交易中止。CLUSTER,声明... FOR UPDATE,和触发器在追加优化表中不予支持。
选择行存储或列存储
Greenplum的提供存储取向模式的选择:行,列,或两者的组合。本主题提供了选择最适宜的储藏定位为一个表的一般准则。用你自己的数据和查询工作负载的性能进行评估。
• 面向行存储: 适合OLTP工作负载。多行的迭代交易,一次需要多列。
• 列存储: 适合数据仓库负载,在几个列上聚合运算,只对单个列进行不定期的更新。
对于大多数通用或混合负载,面向行的存储提供的灵活性和性能的最佳组合。不过,也有使用的情况下,一个面向列的存储模型提供了更高效的I / O和存储。考虑在一个表的存储模型的方向作出决定时,下列要求:
• 表数据的更新。如果您加载和频繁更新的表中的数据,选择一个面向行的堆表。面向列的表存储仅适用于附加优化表。见堆存储更多的信息SeeHeapstorage for moreinformation.
• 频繁插入. 如果行被频繁插入到表中,考虑面向行的模式。面向列的表没有对写操作进行优化,比如对一个行的列值必须写入到磁盘上的不同的地方。
• 在查询请求的列数。如果你通常要求全部或大部分列在SELECT列表或WHERE查询子句,考虑面向行的模式。面向列的表是最适合于聚集一列,其中WHERE或HAVING谓语也对聚合列的许多值的查询。例如:
SELECTSUM(salary)…
SELECTAVG(salary)…WHERE salary > 10000
或其中的WHERE谓词是对单个列,并返回一个相对小数目的行。例如:
SELECT salary,dept …WHERE state='CA'
• 表中的列数。当需要在同一时间许多列时,或当一个表的行大小是比较小的面向行的存储是更有效的。面向列的表可以提供与在那里你在你的查询访问列的一小部分多列的表更好的查询性能。
• 压缩。列数据具有相同的数据类型,因此,存储大小的优化是在不是在面向行的数据可面向列的数据资料。例如,许多压缩方案使用相邻数据的相似性来压缩。压缩比越高,随机查询越困难,因为数据必须被解压后才能访问。
创建一个列存储表
CREATE TABLE命令的WITH子句指定表的存储选项。默认值是一个面向行的堆表。使用面向列的存储表必须是追加优化表。例如,创建一个面向列的表:
=> CREATETABLE bar (a int, b text)
WITH(appendonly=true, orientation=column)
DISTRIBUTED BY(a);
使用压缩 (Append-Optimized Tables Only)
在GPDB中追加优化表有两种内置颜色方式:
• 表级压缩,在整个表的范围使用压缩。
• 列级压缩。对单独的列使用压缩. 你可以对不同的列使用不同的压缩算法。
Table 28:Compression Algorithms for Append-Optimized Tables
表存储模式 |
Available Compression Types |
压缩算法 |
行 |
表级 |
zlib and QUICKLZ |
列 |
列级和表级 |
RLE TYPE, ZLIB, and QUICKLZ |
当选择附加优化表的压缩类型和级别,考虑以下因素:
• CPU 使用率。段的系统必须有足够的CPU功率来压缩和解压数据。
• 压缩比/磁盘大小。尽量减少磁盘大小是一个因素,还要考虑到压缩和扫描数据所需的时间和CPU的能力。找到最佳的设置,而不会导致过长压缩时间或慢扫描速率有效压缩数据。
• 压缩文件的速度。 QuickLZ压缩相比于zlib使用较少的 CPU 和数据压缩比。Zlib压缩速度慢但压缩比高。
例如, 在压缩级别1(compresslevel= 1),QuickLZ和zlib具有相当的压缩比,但压缩速度不同。使用的zlib在compresslevel = 6能显著增加压缩比相比QuickLZ,尽管具有较低的压缩速度。
• 减压/扫描速率的速度。 使用压缩存储的追加优化表的性能取决于硬件、查询优化设置、以及其他因素。执行比较测试,以确定您的环境的实际性能。
注意:不要创建在使用压缩文件系统压缩附加优化表。如果,你的分段数据目录所在的文件系统是一个压缩文件系统,您的附加优化表一定不能使用压缩。
用压缩附加优化表的性能取决于硬件,查询优化设置,以及其他因素。Greenplum的建议进行对比测试,以确定您的环境的实际性能。
注:QuickLZ压缩级别只能被设置为1级;没有其他的选项。与zlib压缩级别可以从值1设置 - 4 - 9. RLE压缩级别可以从1个值进行设置。
编码子句指定单独的列压缩类型和级别。当编码子句与冲突使用条款,ENCODING子句比WITH子句更高的优先级。
创建压缩表
CREATE TABLE命令的WITH子句声明表的存储选项。使用压缩表必须附加优化表。例如,要创建在5压缩级别zlib压缩追加优化表:
=> CREATE TABLE foo (a int, b text)
WITH(appendonly=true, compresstype=zlib, compresslevel=5);
检查附加优化表的压缩和分布
Greenplum的提供了内置功能检查压缩比和追加优化表的分布。函数接受任何对象ID或表名。你可以用一个模式名限定表名。
Table 29:Functions for compressed append-optimized table metadata
Function |
Return Type |
Description |
get_ao_distribution(name) get_ao_distribution(oid) |
Set of (dbid, tuplecount) rows |
示出了在阵列追加优化表中的行的分布。返回一组行,每一个包括存储在段的段DBID和元组的数量. |
get_ao_compression_ratio(name) get_ao_compression_ratio(oid) |
float8 |
计算用于压缩的追加优化表中的压缩率。如果信息不可用,此函数返回-1的值。 |
压缩比被返回作为公共比例。例如,3.19,或3.19一个返回值:1,这意味着未压缩表略微大于三倍压缩表的大小。表中的分布形式返回一组行指示多少元组被存储在每个段。例如,在与DBID值从0-3四个主要部分的系统,函数返回类似于以下四行:
=# SELECTget_ao_distribution('lineitem_comp');
get_ao_distribution
---------------------
(0,7500721)
(1,7501365)
(2,7499978)
(3,7497731)
(4 rows)
Support forRun-length Encoding
Greenplum的数据库支持列级压缩运行长度编码(RLE)。 RLE数据压缩存储重复的数据作为单个数据值和计数。 例如在一个具有日期和描述这两个列的表中, 有200,000 的条目存储 date1以及400,000条目存储date2, RLE 对date1的压缩和date2类似(RLEcompression for the date field is similar to date1 200000 date2 400000.)。 RLE 对那些重复很少的数据压缩比不大,从而导致文件大小大大的增加。
有四个层次RLE压缩的。随着层级的升高,压缩比逐步升高,但降低了压缩速度。
Greenplum的数据库版本4.2.1及更高版本支持面向列的RLE压缩。你可以用RLE来压缩备份一个表,当你打算恢复到Greenplum数据引擎的早期版本的表,需要在备份前更改表为没有压缩或在早期版本(ZLIB或QUICKLZ)支持的压缩类型。
在Greenplum数据4.3.3或更高版本,Greenplum数据引擎对数据类型BIGINT,INTEGER,DATE,TIME或TIMESTAMP在RLE压缩类型中结合了增量压缩。增量压缩算法是基于连续列值之间的变化,并且设计成当数据按排序顺序或当压缩应用到排序后的顺序数据被装载到改进压缩。当Greenplum的数据库升级到4.3.3,这些规则适用于那些与RLE压缩的列中的数据:
• 现有列数据,只有RLE压缩压缩。
• 新数据与增量压缩在类型支持它的列RLE压缩相结合压缩。
如果需要从Greenplum4.3.3切换到Greenplum4.3.2,建议采取以下步骤。
1. 更改使用了RLE压缩的追加优化的,列存储的表,将其改成使用无压缩或压缩型ZLIB或QUICKLZ。
2. 备份数据库。
注意:如果您的备份使用RLE压缩列从Greenplum数据4.3.3表,您可以在Greenplum数据4.3.2恢复表。然而,在Greenplum数据引擎4.3.2压缩RLE压缩,不RLE压缩与增量压缩相结合。
Note: If youbackup a table that uses RLE column compression from a Greenplum Database4.3.3, you can restore the table in Greenplum Database 4.3.2. However, thecompression in the Greenplum Database 4.3.2 is RLE compression, not RLEcompression combined with delta compression.
添加列级压缩
您可以在以下存储指令添加到与列方向附加优化表列:
• 压缩类型
• 压缩等级
• 列的块大小
添加使用CREATE TABLE存储指令,ALTER TABLE和CREATE TYPE命令。
下面列出了存储指令和每种指令可能的值。
Table 30:Storage Directives for Column-level Compression
Name |
Definition |
Values |
Comment |
COMPRESSTYPE |
Type of compression. |
zlib: deflate algorithm quicklz: fast compression rle type: run-length encoding none: no compression |
Values are not case- sensitive. |
Name |
Definition |
Values |
Comment |
COMPRESSLEVEL |
Compression level. |
zlib compression: 1-9 |
1 is the fastest method with the least compression. 1 is the default. 9 is the slowest method with the most compression. |
QuickLZ compression: 1 - use compression |
1 is the default. |
||
rle type compression: 1-4 1 - apply RLE only 2 - apply RLE then apply zlib compression level 1 3 - apply RLE then apply zlib compression level 5 4 - apply RLE then apply zlib compression level 9 |
1 is the fastest method with the least compression. 4 is the slowest method with the most compression. 1 is the default. |
||
BLOCKSIZE |
The size in bytes for each block in the table |
8192 - 2097152 |
The value must be a multiple of 8192. |
下面是添加存储指令的格式
[ENCODING ( storage—directive)]
ENCODING 关键词需要存储的三个部分:where the word ENCODING is requiredand the storage directive has three parts:
• 指令名称
• 等号
• 规范
独立的多个存储指令用逗号。适用的存储指令到单个列或指定为默认为所有列,如图以下CREATETABLE条款。
General Usage:
column_namedata_type ENCODING ( storage_directive [, … ] ), …
COLUMNcolumn_name ENCODING ( storage_directive [, … ] ), …
DEFAULT COLUMNENCODING ( storage_directive [, … ] )
Example:
C1 charENCODING (compresstype=quicklz, blocksize=65536)
COLUMN C1ENCODING (compresstype=zlib, compresslevel=6, blocksize=65536)
DEFAULT COLUMNENCODING (compresstype=quicklz)
默认压缩值
如果没有定义的压缩类型,压缩级别和块大小,默认为不进行压缩,和块大小被设定为服务器配置参数block_size。
压缩设置的优先级
列压缩设置是从表级别的分区级子分区级别继承。最低级别的设置具有优先权。
• 在表级别指定列压缩设置将覆盖整个表的压缩设置。
• 对分区指定列压缩设置覆盖在列或表级别的压缩设置。
• 为子分区指定列压缩设置将覆盖该分区,列或表级别的压缩设置。
• 当WITH子句的编码条款冲突,ENCODING子句比WITH子句更高的优先级。
注:INHERITS子句中不允许包含存储指令或列引用存储指令的表。
使用LIKE子句创建的表忽略存储指令和列存储的参考指令。
最佳位置列压缩设置
最好的做法是在数据所在级别设置列压缩设置。参见例5,其示出了具有的2 RLE_TYPE压缩分区深度的表被添加到在子分区水平一列。
存储指令的例子
以下示例显示了CREATE TABLE语句中使用存储指令。
Example 1
在这个例子中,列c1使用的zlib压缩,并使用由系统定义的块大小。列C2与quicklz压缩,并使用65536,列C3的块尺寸是不压缩的,并使用由系统定义的块大小。
CREATE TABLET1 (c1 int ENCODING (compresstype=zlib),
c2 charENCODING (compresstype=quicklz, blocksize=65536), c3 char WITH (appendonly=true, orientation=column);
Example 2
在这个例子中,列c1使用的zlib压缩,并使用由系统定义的块大小。列C2使用quicklz压缩,并数据块大小65536。列C3的块尺寸是使用RLE_TYPE压缩的,并使用由系统定义的块大小。
CREATE TABLET2 (c1 int ENCODING (compresstype=zlib),
c2 charENCODING (compresstype=quicklz, blocksize=65536), c3 char,
COLUMN c3ENCODING (compresstype=RLE_TYPE)
) _
WITH(appendonly=true, orientation=column)
Example 3
在这个例子中,列C1被使用的zlib压缩,并使用由系统定义的块大小。列C2使用quickiz压缩,块大小65536。列C3使用zlib的,并使用由系统所定义的块大小压缩。注意,c3列使用的zlib(未RLE_TYPE)中的分区,因为该列存储分区子句中具有优先于该表的列定义的存储指令。
CREATE TABLE T3 (cl int ENCODING (compresstype=zlib),
c2 char ENCODING(compresstype=quicklz, blocksize=65536), c3 char, COLUMN c3 ENCODING(compresstype=RLE_TYPE)) WITH (appendonly=true, orientation=column)
PARTITION BY RANGE (c3)(START ('1900-01-01'::DATE)
END ('2100-12-31'::DATE),
COLUMN c3 ENCODING (zlib));
Example 4
在这个例子中,CREATE TABLE为C1分配的zlibcompresstype存储指令。 C2列没有存储指令,并继承了默认列ENCODING子句的压缩类型(quicklz)和块大小(65536)。
列C3的编码方式子句定义的压缩类型,RLE_TYPE。默认列ENCODING子句定义C3的块大小,65536。
为特定列定义的编码子句覆盖默认编码子句,因此列C4现在没有的压缩类型和缺省块大小。
CREATE TABLE T4 (c1 intENCODING (compresstype=zlib),
c2 char,
c4 smallint ENCODING(compresstype=none),
DEFAULT COLUMN ENCODING(compresstype=quicklz,
blocksize=65536),
COLUMN c3 ENCODING(compresstype=RLE_TYPE)
)
WITH(appendonly=true, orientation=column);
Example 5
这个例子创建追加优化列存储表T5。 T5有两个分区,P1和P2,其每一个具有子分区。每个子分区具有编码的条款:
•分区P1的子分区SP1编码子句定义列i的压缩类型的zlib和块大小为65536。
•分区P2的子分区SP1编码条款定义列i的压缩类型rle_type和块大小是默认值。 K列使用默认的压缩和它的块大小为8192。
CREATE TABLE T5(i int, jint, k int, l int)
WITH (appendonly=true,orientation=column)
PARTITION BY range(i)SUBPARTITION BY range(j)
(
p1 start(1) end(2)
( subpartition sp1start(1) end(2)
column iencoding(compresstype=zlib, blocksize=65536)
),
partition p2 start(2)end(3)
( subpartition sp1start(1) end(2)
column iencoding(compresstype=rle_type)
column kencoding(blocksize=8192)
)
);
为了说明如何压缩列添加到现有的表使用ALTER TABLE命令的示例,请参阅添加压缩列表。
在Type命令中添加压缩
您可以定义压缩类型来简化列压缩陈述。例如,下面的CREATE TYPE命令定义的压缩型,comptype,指定quickiz压缩。
其中,comptype定义为:
CREATE TYPEcomptype (
internallength = 4,
input = comptype_in,
output = comptype_out,
alignment = int4,
default = 123,
passedbyvalue,
compresstype="quicklz",
blocksize=65536,
compresslevel=1
);
然后,可以使用comptype在CREATE TABLE命令为字段指定quicklz压缩:
CREATE TABLE t2 (c1 comptype)
WITH(APPENDONLY=true, ORIENTATION=column);
有关创建和加入压缩参数类型的信息,请参阅CREATE TYPE。有关在类型改变压缩规格的信息,请参见ALTER TYPE。
选择块大小
块大小的大小,以字节为单位,对表中的每个块。块大小必须是8192和2097152字节之间,并且是8192的倍数,默认为32768。
指定较大的块大小可以消耗大量的内存。块大小确定在存储层缓冲。 Greenplum的维护每个分区的缓冲区,且每列在面向列的表。与许多分区或列的表消耗大量的内存。
更改表
ALTER TABLE命令更改了表的定义。使用ALTER TABLE更改为列定义,分配政策,存储模式和分区表结构等属性(参见维护分区表)。例如,在非空约束添加到表列:
=> ALTER TABLE address ALTER COLUMNstreet SET NOT NULL;
更改表分布
ALTER TABLE提供的选项更改表的分配政策。当表分发选项改变,表中的数据被重新分配在磁盘上,其可以是资源密集型的。您也可以使用现有的分配政策重新分配表中的数据。
更改分布策略
对于分区表,改变分配政策递归应用到子分区。此操作将保留所有权和该表的所有其他属性。例如,下面的命令使用CUSTOMER_ID作为分布键将数据重新分布到所有段。
ALTER TABLE sales SETDISTRIBUTED BY (customer_id);
当您更改表的散列分布表中的数据会自动重新分配。分配策略改变为随机分布不会导致被重新分配的数据。例如,下面的ALTER TABLE命令没有立竿见影的效果:
ALTER TABLEsales SET DISTRIBUTED RANDOMLY;
重新分发表数据
为了重新发布了随机分配政策(或当哈希分配政策没有改变)表表中的数据使用REORGANIZE= TRUE。重组数据可能有必要纠正数据歪斜问题,或当段资源被添加到系统。例如,下面的命令多个使用现行分配政策,包括随机分布各阶层重新分配表中的数据。
ALTER TABLE sales SET WITH (REORGANIZE=TRUE);
更改表存储模型
表存储,压缩和取向只能在表创建时声明。要改变存储模型,你必须创建正确的存储选项表,原始表数据加载到新表,删除原表,并与原表的名称重命名新表。并且还必须重新对表进行授权。例如:
CREATE TABLE sales2 (LIKEsales)
WITH (appendonly=true,compresstype=quicklz,
compresslevel=1, orientation=column);
INSERT INTO sales2 SELECT* FROM sales;
DROP TABLE sales;
ALTER TABLE sales2 RENAMETO sales;
GRANT ALL PRIVILEGES ONsales TO admin;
GRANTSELECT ON sales TO guest;
SeeSplitting a Partition to learn how to change the storagemodel of a partitioned table.
添加压缩列到一个表
使用ALTER TABLE命令来压缩列添加到表。所有的选项和约束在添加列级压缩描述压缩列适用于使用ALTER TABLE命令添加列。
下面的示例演示如何使用zlib压缩列添加到表,T1。
ALTER TABLE T1
ADD COLUMN c4int DEFAULT 0 ENCODING (COMPRESSTYPE=zlib);
压缩设置的继承
被添加到具有与子分区压缩设置的表分区继承了子分区压缩设置。下面的示例演示如何创建子分区编码表,然后改变它添加分区。
CREATE TABLE ccddl (i int,j int, k int, l int)
WITH
(APPENDONLY = TRUE,ORIENTATION=COLUMN)
PARTITION BY range(j)
SUBPARTITION BY list (k)
SUBPARTITION template(
SUBPARTITION sp1 values(1,2, 3, 4, 5),
COLUMN iENCODING(COMPRESSTYPE=ZLIB),
COLUMN jENCODING(COMPRESSTYPE=QUICKLZ),
COLUMN kENCODING(COMPRESSTYPE=ZLIB),
COLUMN lENCODING(COMPRESSTYPE=ZLIB))
(PARTITION p1 START(1)END(10),
PARTITION p2 START(10)END(20));
ALTER TABLE ccddl
ADD PARTITION p3 START(20)END(30);
运行ALTER TABLE命令创建表ccddl名为ccddi_i_prt_p3和ccddi_i_prt_p3_2_prt_spi的分区。分区ccddi_i_prt_p3继承子分区SPI的不同的压缩编码。
删除表
DROP TABLE命令从数据库删除表。例如:
DROP TABLEmytable;
要清空行的表不删除表定义,使用delete或truncate。例如:
DELETE FROMmytable;
TRUNCATEmytable;
DROP TABLE总是删除任何索引,规则,触发器和约束存在目标表。指定CASCADE下降由视图引用的表。 CASCADE删除相关视图。
大表分区
表分区能够支持非常大的表,如事实表,由逻辑上划分为更小,更易管理的片段。分区表可以通过允许Greenplum数据引擎查询优化器只扫描满足条件的记录,而不是扫描一个大表的所有内容给定查询所需的数据,提高查询性能。.
• 关于表分区
• 表分区策略制定
• 创建分区表
• 加载分区表
• 验证分区策略
• 查看分区设置
• 维护分区表
关于分区表
分区不改变表数据在段的物理分布。表分布是物理:Greenplum数据物理划分分区表和非分区表跨段,以使并行查询处理。表分区是逻辑:Greenplum数据逻辑上划分大表以提高查询性能和方便数据仓库的维护任务,如旧数据从数据仓库移除。
Greenplum的数据库支持:
• 范围分区:根据数值范围的数据,如日期或价格。
• 列表分布: 根据列表的数据来划分数据,例如销售区域或产品线
• 两种类型的组合
Figure 14: Example Multi-levelPartition Design
GreenplumDatabase中的数据分区
Greenplum将数据拆分成不同部分(也称为分区),以使大规模并行处理。表分区中创建一个使用PARTITIONBY TABLE(以及可选的SUBPARTITIONBY)子句。分区创建具有子表(或子表)中的一个或多个级别的一个顶层(或父)表。在内部,Greenplum数据创建的顶层表及其底层分区,类似的PostgreSQLINHERITS子句的功能之间的继承关系。
Greenplum的使用创建表的过程定义创建具有鲜明的CHECK约束,这限制了表可以包含数据的每个分区的分区标准。查询优化器使用CHECK约束来确定扫描到满足给定查询谓词的表分区。
Greenplum的系统目录存储了进行分区层次结构信息,以便插入到顶层父表行正确地传播到子表的分区。要改变分区设计和表结构,使用ALTER TABLE的PARTITION子句改变父表。
将数据插入到一个分区表,您指定的根分区表,用CREATE TABLE命令创建的表格。您也可以在INSERT命令中指定的分区表的树叶子表。如果数据是无效的指定树叶子表,则返回错误。不支持指定在DML命令非叶或非root分区表。
表分区策略制定
并非所有的表都适合分区。如果下面的全部或大部分问题的答案都是很定的,则表分区是用于提高查询性能的可行数据库设计策略。如果答案是否定的,则表分区不是适合该表的放哪。测试你的设计策略,以确保查询性能能达到预期。
• 该表是否足够大? 大的事实表适合分区,如果你在一个具有上百万甚至数十亿的表,那从逻辑上将这些数据分成较小的数据块能达到较好的性能优势。对于只有几千行甚至更小的表,你会发现维护分区的管理开销将超过任何性能的提升。
• 你是否遇到性能不佳? 正如任何性能调整举措,表应该只有当对这个表的查询比预期正在产生较慢的响应时间进行分区。
• 你的查询谓词具有明确的访问模式? 检查你的查询工作负载的WHERE子句并查找访问数据表的列。例如,如果你的大多数查询倾向于按日期查找记录,则按月或按周的日期分区设计可能是有益的。或者,如果你倾向于按地区来访问记录,可以考虑一个列表分区设计,按区域划分表。
• 你的数据仓库是否保持历史数据的窗口? 分区设计的另一个考虑是维护历史数据组织的业务需求。例如,你的数据仓库可能会要求您保留数据,过去十二个月。如果数据按月分区,您可以轻松地从仓库中删除最早的每月分区,当前的数据加载到最新的每月分区
• 可以把数据分为基于某种定义标准有所相等的部分? 选择分组标准将尽可能均匀划分数据成为可能。如果分区包含的记录相对相等数量,查询的性能提高了基于创建的分区的数量。例如,通过将大表分为10个分区,查询将执行快10倍以上,将针对未分区表,前提是该分区被设计为支持查询的条件。
不要创建比实际需要更多的分区。创建分区太多可以减缓的管理和维护工作,如vacuum,恢复段,扩大集群,检查磁盘使用情况,等等。
分区不会提高查询性能,除非查询优化器可以根据查询谓词消除分区。该扫描每个分区运行的查询比如果表不分区慢,所以要避免分区,如果几个查询的实现分区消除。检查查询的解释计划,以确保分区被淘汰。见仿形查询更多关于分区消除。SeeQuery Profiling for moreabout partition elimination.
对多层次分区要非常小心,因为分区中的文件数量增长速度很快。例如,如果一个表是由白天和城市来分区,有数据和1000个城市的1000天,分区的总数为一百万。面向列的表存储在一个物理表的每一列,因此,如果这个表具有100列,该系统将需要管理100亿个文件的表。
在确定在一个多层次分区策略之前,请考虑使用位图索引一个级别的分区。索引会降低数据加载速度,因此建议与您的数据和架构性能测试的最佳策略决定。
创建分区表
当你用CREATETABLE创建它们,你分区表。本主题提供了SQL语法的示例与各种分区设计创建表。
为了分区一个表:
1. 确定分区设计:日期范围,数值范围, 或值的列表。
2. 确定分区表的列.
3. 确定分区的层级。例如,您可以创建每个月的日期范围分区表,然后通过子分区销售区域每月分区。
4. 定义日期范围分区表
• 定义数字范围分区表
• 定义列表分区表
• 定义多级分区
• 分区现有的表
定义日期范围分区表
日期范围分区表使用单个日期或时间戳列作为分区键列。如果需要创建子分区,您可以使用相同的分区键列。例如,先按照每月进行分区,再将每月按照天进行分区。在进行分区时,最好以最精细的水平进行分区。例如,按日期分区的表,可以按天分区一年365个分区,而不是按照年进行分区,然后是按照月创建子分区,在对每个月创建天的分区。一个多层次的设计可以减少查询计划的时间,但平坦的分区设计,运行速度更快。
你可以有Greenplum数据通过给START值,终值,以及EVERY子句定义分区增量值自动生成的分区。默认情况下,启动值总是包容和最终值始终是排他的。例如:
DISTRIBUTEDBY (id)
PARTITIONBY RANGE (date)
(START (date '2008-01-01') INCLUSIVE
END(date '2009-01-01') EXCLUSIVE
EVERY(INTERVAL '1 day') );
你也可以对每个分区进行分布的命名,例如:
CREATETABLE sales (id int, date date, amt decimal(10,2))
DISTRIBUTEDBY (id)
PARTITIONBY RANGE (date)
(PARTITION Jan08 START (date '2008-01-01') INCLUSIVE ,
PARTITIONFeb08 START (date '2008-02-01') INCLUSIVE ,
PARTITIONMar08 START (date '2008-03-01') INCLUSIVE ,
PARTITIONApr08 START (date '2008-04-01') INCLUSIVE ,
PARTITIONMay08 START (date '2008-05-01') INCLUSIVE ,
PARTITIONJun08 START (date '2008-06-01') INCLUSIVE ,
PARTITIONJul08 START (date '2008-07-01') INCLUSIVE ,
PARTITIONAug08 START (date '2008-08-01') INCLUSIVE ,
PARTITIONSep08 START (date '2008-09-01') INCLUSIVE ,
PARTITIONOct08 START (date '2008-10-01') INCLUSIVE ,
PARTITIONNov08 START (date '2008-11-01') INCLUSIVE ,
PARTITIONDec08 START (date '2008-12-01') INCLUSIVE
END(date '2009-01-01') EXCLUSIVE );
除了最后一个必须声明END值之外,你不必为每个分区都声明END值。在这个例子中,Jan08的END值就是Feb08的开始值,相当于PARTITION Jan08 START(date '2008-01-01') INCLUSIVE , END (date '2008-02-01') EXCLUSIVE,下一个分区的开始值就自动是上一个分区的结束值。
定义一个数值范围的分区表
数字范围分区表使用一个单一的数字数据类型列作为分区键列。例如:
CREATE TABLE rank (id int,rank int, year int, gender
char(1), count int)
DISTRIBUTED BY (id)
PARTITION BY RANGE (year)
( START (2001) END (2008)EVERY (1),
DEFAULTPARTITION extra );
有关默认分区的详细信息,请参阅添加默认分区。
定义列表分区表
列表分区表可以使用任何数据类型列,使平等的比较作为分区键列。列表分区也可以具有多列(复合)分区键,而范围分区只允许一个单一的列作为分区键。对于列表分区,你必须对你要创建的每个分区的(列表值)进行声明。例如:
CREATE TABLE rank (id int,rank int, year int, gender
char(1), count int )
DISTRIBUTED BY (id)
PARTITION BY LIST (gender)
( PARTITION girls VALUES('F'),
PARTITION boys VALUES('M'),
DEFAULTPARTITION other );
Note: Thecurrent Greenplum Database legacy optimizer allows list partitions withmulti-column (composite) partition keys. A range partition only allows a singlecolumn as the partition key. The Pivotal Query Optimizer does not supportcomposite keys, so Pivotal does not recommend using composite partition keys.
For moreinformation about default partitions, see Addinga Default Partition.
注意:当前Greenplum数据引擎旧系统优化器允许在列表分区上使用多列(复合)分区键。一系列分区只允许一列作为分区键。Pivotal的查询优化器不支持组合键,因此Pivotal不建议使用复合分区键。
有关默认分区的详细信息,请参阅添加默认分区。
Defining Multi-level Partitions
您可以创建一个多层次分区且包含子分区的设计。使用子分区模板,确保每个分区都有相同的子分区的设计,包括您以后添加的分区。例如,下面的SQL创建如图14所示的两级分区设计:
CREATE TABLE sales(trans_id int, date date, amount
decimal(9,2), region text)
DISTRIBUTED BY (trans_id)
PARTITION BY RANGE (date)
SUBPARTITION BY LIST(region)
SUBPARTITION TEMPLATE
( SUBPARTITION usa VALUES('usa'),
SUBPARTITION asia VALUES('asia'),
SUBPARTITION europe VALUES('europe'),
DEFAULT SUBPARTITIONother_regions)
(START (date '2011-01-01')INCLUSIVE
END (date '2012-01-01')EXCLUSIVE
EVERY (INTERVAL '1month'),
DEFAULTPARTITION outlying_dates );
下面的例子显示了一个三级分区设计,其中销售表由年份,然后一个月,然后区域划分。子分区模板条款确保每个分区每年有相同的子分区结构。本示例声明在层次结构的每个级别一个默认分区。
CREATETABLE p3_sales (id int, year int, month int, day int,
regiontext)
DISTRIBUTEDBY (id)
PARTITIONBY RANGE (year)
SUBPARTITION BY RANGE (month)
SUBPARTITION TEMPLATE (
START (1) END (13) EVERY (1),
DEFAULT SUBPARTITION other_months )
SUBPARTITION BY LIST (region)
SUBPARTITION TEMPLATE (
SUBPARTITION usa VALUES ('usa'),
SUBPARTITION europe VALUES('europe'),
SUBPARTITION asia VALUES ('asia'),
DEFAULT SUBPARTITION other_regions)
( START(2002) END (2012) EVERY (1),
DEFAULT PARTITION outlying_years );
注意:当您创建的范围多层次的分区,很容易造就了一大批子分区,有的含很少或根本没有数据。这可以添加许多条目到系统表,这增加了优化和执行查询所需要的时间和存储器。增加射程间隔或选择不同的分区策略,以减少创建的子分区的数量。
对已存在的表进行分区
表只能在创建时分配。如果您有要分区表,你必须创建一个分区表,从原来的表中的数据加载到新表,删除原表,并与原表的名称重命名分区表。您还必须重新授予任何表权限。例如:
CREATE TABLE sales2 (LIKEsales)
PARTITION BY RANGE (date)
( START (date'2008-01-01') INCLUSIVE
END (date '2009-01-01')EXCLUSIVE
EVERY (INTERVAL '1 month'));
INSERT INTO sales2 SELECT* FROM sales;
DROP TABLE sales;
ALTER TABLE sales2 RENAMETO sales;
GRANT ALL PRIVILEGES ONsales TO admin;
GRANTSELECT ON sales TO guest;
分区表的限制
对于每个分区级分区表最多可以有32,767分区都有。
分区表上的主键或唯一约束,必须包含所有分区列。唯一索引可以省略分区列;然而,它仅在分区表的各部分起作用,而不是在分区表作为一个整体。
Pivotal的查询优化器支持统一的多层次的分区表。如果Pivotal查询优化器已启用,分区表的多层次的不统一,Greenplum数据引擎就使用了传统的查询优化器。有关统一的多层次的分区表信息,请参阅关于统一多层次的分区表。AboutUniform Multi-level Partitioned Tables.
如果分区表在创建时有subparition或则分区包含子分区,则将分区的叶子节点和外部表进行交换时不予支持。
有关使用外部表交换叶子分区信息,请参阅更换一个叶子分区与外部表。seeExchanginga Leaf Child Partition withan External Table.
这些是分区表的叶子分区是外部表时的限制:
• 对包含外部表分区的分区表运行的查询与旧查询优化器(legacyquery optimizer)执行.
• 外部表分区是一个只读外部表。命令尝试访问或在外部表分区修改数据返回一个错误。例如:
• INSERT,DELETE和UPDATE命令,试图改变外部表分区的数据返回一个错误。
• TRUNCATE命令返回一个错误。
• COPY命令不能将数据复制到一个分区表更新外部表的分区。
• COPY命令,试图从外部表分区复制返回一个错误,除非你指定与COPY命令将忽视任何外部PARTITIONS子句。如果指定该子句,数据没有从外部表分区复制。
无法采用COPY命令来处理叶子节点是外部表的分区表,改为使用SQL查询来复制数据。例如,如果表my_saies包含一个与叶子表是外部表,此命令将数据发送到标准输出:
COPY (SELECT * frommy_sales ) TO stdout
• vacuum 命令会跳过外部表。
• 如下命令仅能在外部表的数据没有发生变化时才能使用。否则,将返回错误。
• 添加或删除列。
• 更改列的数据类型
• 如果分区表中包含外部表分区,更改这些分区操作不支持:
• 设置一个子分区模板。
• 更改分区属性。
• 创建默认分区。
• 设置分配政策。
• 设置或删除列的NOT NULL约束。
• 添加或删除约束。
• 拆分外部分区。
• Greenplum的数据库实用程序gpcrondump在分区表的叶子子分区是一个只读的外部表时不会备份其数据。
加载分区表
您所创建的分区表结构之后,顶级父表是空的。数据路由到下一级子表的分区。在一个多级分区的设计,仅在层次结构的底部子分区可以包含数据。
不能被映射到一个子表分区的行被拒绝,并且加载失败。为了避免在加载时被拒绝取消映射行,用默认分区定义分区层次。不符合一个分区的CHECK约束的任何行加载到默认分区。请参阅添加默认分区。
在运行时,查询优化器扫描整个表继承层次结构,并使用检查表的约束条件来确定扫描到满足查询的条件,子表的分区。默认的分区(如果您的层次结构有一个)总是被扫描。包含数据的默认分区减慢整个扫描时间。
当您使用COPY或INSERT将数据加载到一个父表,将数据自动重新路由到正确的分区,就像一个普通的表。
最佳实践数据装入分区表是创建一个中间临时表,加载它,然后交换到你的分区设计。
验证你的分区策略
当表根据查询谓词分区,你可以使用EXPLAIN来验证查询优化器只扫描相关的数据来检查查询计划。
例如,假设销售表日期范围按月分区,并如图Figure 14: Example Multi-level Partition Design. 对于下面的查询:
EXPLAINSELECT * FROM sales WHERE date='01-07-12' AND region='usa';
此查询的查询计划应只显示如下表的表扫描:
• 默认分区返回0-1行(如果你的分区设计有)
• 在2012年1月的分区(sales_1_prt_1)返回0-1行
• 美国地区的子分区(sales_1_2_prt_usa)返回一定数量的行
下面的例子显示了查询计划的相关部分。
-> Seq Scanonsales_1_prt_1 sales (cost=0.00..0.00 rows=0
width=0)
Filter:"date"=01-07-08::date AND region='USA'::text
-> Seq Scanonsales_1_2_prt_usa sales (cost=0.00..9.87
rows=20
width=40)
确保查询优化器不会扫描不必要的分区或子分区(例如,数月或地区的扫描查询谓词指定),以及顶级表,这些表扫描返回0-1行。
TroubleshootingSelective Partition Scanning
以下限制可导致查询计划,显示分区层次结构的非选择性扫描。
•查询优化器可以选择扫描分区表,只有当查询包含使用直接和简单的不变运算符:
=,<,<=,>,>=和<>
•选择性扫描识别不变的函数,但在查询中不能识别易变函数。例如,WHERE子句如date>CURRENT_DATE导致查询优化器选择扫描分区表,但time>TIMEOFDAY没有。
查看你的分区设计
你可以查找有关使用分区的设计pg_partitions视图。例如,看销售表的分区设计:
SELECT partitionboundary,partitiontablename, partitionname,
partitionlevel, partitionrank
FROM pg_partitions
WHEREtablename='sales';
下表和视图显示有关分区表信息。
• pg_partition -跟踪分区表及其继承层次关系。
• pg_parfition_templates-显示使用子分区模板创建的子分区。
• pg_parfition_columns-显示在一个分区设计中使用的分区键列。
有关Greenplum数据系统目录表和视图的信息,请参阅Greenplum数据参考指南。
维护分区表
为了保持分区表,使用ALTER TABLE命令对顶级父表。最常见的情形是丢弃旧分区并添加新的维持在一个范围内的分区设计数据的滚动窗口。您可以转换(交换)旧的分区追加优化的压缩存储格式,以节省空间。如果你在你的分区设计,默认分区,则通过拆分默认分区添加分区。
• 添加分区
• 重命名分区
• 添加默认分区
• 删除分区
• 清空分区
• 交换分区
• 拆分分区
• 修改子分区分模板
• 用外部表交换一个叶子分区
重要提示:当定义和改变分区的设计,使用给定的分区名称,而不是表对象的名称。虽然你可以直接使用SQL命令查询和加载任何表(包括分区表),你只能使用ALTER修改分区表的结构
TABLE…PARTITIONclauses.
分区可以没有命名。如果一个分区没有一个命名,使用下列表达式之一指定部分:分区(值)或)分区
FOR(RANK(number).
添加分区
您可以将分区添加到分区设计ALTER TABLE命令。如果原来的分区设计包括一个子分区模板中定义子分区,新增加的分区是根据该subpartitioned模板。例如:
You can add apartition to a partition design with the alter table command. If theoriginal partition design included subpartitions defined by a subpartition template,the newly added partition is subpartitioned according to that template. 例如:
ALTER TABLE sales ADDPARTITION
START (date '2009-02-01')INCLUSIVE
END(date '2009-03-01') EXCLUSIVE;
如果您在创建该表没有使用子分区模板,可以定义添加分区时,子分区:
ALTER TABLEsales ADD PARTITION
START (date '2009-02-01') INCLUSIVE
END (date '2009-03-01') EXCLUSIVE
( SUBPARTITION usa VALUES ('usa'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe') );
当您添加子分区到一个现有的分区,可以指定分区改变。例如:
ALTER TABLE sales ALTERPARTITION FOR (RANK(12))
ADD PARTITION africa VALUES('africa');
注意:您不能将分区添加到分区的设计,有一个默认的分区。您必须拆分默认分区添加分区。见拆分分区。
重命名一个分区
分区表使用下面的命名约定。分区子表的名称都受到独特的要求和长度的限制。
例如:
sales_1_prt_jan08
对于自动生成的范围分区,其中当没有给出名称的号码被分配:
sales_1_prt_1
要重命名分区子表,重命名顶级父表。在所有相关的子表分区的表名的
ALTER TABLE sales RENAME TO globalsales;
更改关联表的名称:
globalsales_1_prt_1
您可以更改分区的名称以使其更易于识别。例如:
ALTER TABLE sales RENAME PARTITION FOR ('2008-01-01')TO jan08;
更改关联的表名,如下所示:
sales_1_prt_jan08
When altering partitioned tables with the ALTER TABLE command,always refer to the tables by their
partition name (jan08) and not their full tablename (sales_1_prt_jan08).
当使用ALTER TABLE命令改变分区表时,总是被他们的分区名称(jan08),而不是其全部的表名(sales_1_prt_jan08)请参照下表。
注:本表名不能在ALTER TABLE语句分区名。例如,
ALTER TABLE sales... is correct, ALTER TABLEsales_1_part_jan08... is not allowed.
添加默认分区
您可以添加默认分区到分区设计ALTER TABLE命令。
ALTER TABLEsales ADD DEFAULT PARTITION other;
如果你的分区设计,多层次,层次结构中的每一层都必须有一个默认的分区。 例如:
ALTER TABLEsales ALTER PARTITION FOR (RANK(1)) ADD DEFAULT
PARTITIONother;
ALTER TABLEsales ALTER PARTITION FOR (RANK(2)) ADD DEFAULT
PARTITIONother;
ALTER TABLEsales ALTER PARTITION FOR (RANK(3)) ADD DEFAULT
PARTITION other;
如果输入的数据不匹配分区的CHECK约束并没有默认的分区,数据被直接拒绝。默认分区确保不匹配分区的输入数据被插入到默认的分区。
删除分区
您可以使用ALTER TABLE命令分区设计删除分区。当您删除具有子分区分区的子分区(在众人的数据)都自动删除。对于范围分区,它是常见的旧数据被卷出的数据仓库的从范围删除较早的分区。例如:
ALTER TABLE sales DROP PARTITION FOR (RANK(1));
清空分区
您可以使用截断ALTER TABLE命令的分区。当您截断有子分区分区时,子分区将自动truncate。
ALTER TABLEsales TRUNCATE PARTITION FOR (RANK(1));
交换分区
您可以通过交换ALTER TABLE命令的分区。交换分区代替现有分区交换一个表。只能在分区层次结构的最低层次交换分区(只包含数据分区可以交换)。
分区交换可以为数据加载非常有用。例如,加载一个临时表和交换表加载到你的分区设计。您可以使用分区汇改追加优化表较早的分区的存储类型。例如:
CREATETABLE jan12 (LIKE sales) WITH (appendonly=true);
INSERT INTOjan12 SELECT * FROM sales_1_prt_1 ;
ALTER TABLEsales EXCHANGE PARTITION FOR (DATE '2012-01-01')
WITH TABLE jan12;
注意:此实施例指的是表销售的单级定义,加入并在前面的例子中改变之前的分区。
警告:如果指定without validation,必须确保你正在交换为现有的分区上的表的数据是符合分区上的限制条件。否则,对分区表的查询可能返回不正确的结果。
在Greenplum的数据库服务器配置参数gp_enable_exchange_default_partition控制对Exchange默认分区条款的可用性。该参数的默认值是关闭的,该条款不可用,如果在指定条款Greenplum数据引擎会返回一个错误
ALTER TABLE命令。
有关参数的信息,请参阅Greenplum数据参考指南“服务器配置参数”。
警告:之前你交换的默认分区,则必须确保在表中的数据进行交换,新的默认分区,有效期为默认分区。例如,在新的默认分区中的数据不能包含将在分区表中的其他叶子分区有效数据。否则,对分区表的查询与交换默认的分区是由Pivotal查询优化器执行可能返回不正确的结果。
拆分分区
拆分分区划分一个分区为两个分区。您可以使用ALTER TABLE命令来分割分区。可以拆分只在分区层次结构的最低层次的分区:仅包含数据可以分割分区。您指定的分裂值进入后者的分区。
例如,每月分区分成两个与含有日期1月1日至15日的第一个分区和含有日期1月16日至31日的第二个分区:
ALTER TABLE sales SPLITPARTITION FOR ('2008-01-01')
AT ('2008-01-16')
INTO(PARTITION jan081to15, PARTITION jan0816to31);
如果你的分区设计有一个默认的分区,则必须拆分默认分区添加分区。
当使用INTO子句指定当前默认的分区作为第二分区名称。例如,拆分默认范围分区增加一个新的每月分区2009年1月:
ALTER TABLE sales SPLITDEFAULT PARTITION
START ('2009-01-01')INCLUSIVE
END ('2009-02-01')EXCLUSIVE
INTO(PARTITION jan09, default partition);
修改分区模板
使用ALTER TABLE SET SUBPARTITION模板修改分区表的子分区模板。加你设置一个新的子分区模板分区后有新的分区设计。现有分区不会被修改。
以下示例更改该分区表的子分区模板:
CREATETABLE sales (trans_id int, date date, amount decimal(9,2), region text)
DISTRIBUTED BY (trans_id)
PARTITION BY RANGE (date)
SUBPARTITION BY LIST (region)
SUBPARTITION TEMPLATE
( SUBPARTITION usa VALUES ('usa'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe'),
DEFAULT SUBPARTITION other_regions )
( START (date '2014-01-01') INCLUSIVE
END (date '2014-04-01') EXCLUSIVE
EVERY (INTERVAL '1 month') );
这个ALTER TABLE命令修改了子分区的模板。
ALTER TABLE sales SETSUBPARTITION TEMPLATE
( SUBPARTITION usa VALUES('usa'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe'),
SUBPARTITION africa VALUES ('africa'),
DEFAULT SUBPARTITION regions );
当您添加表的销售日期范围分区,包括非洲新的区域列表子分区。例如,下面的命令创建子分区美国,亚洲,欧洲,非洲和默认分区命名其他:
ALTER TABLEsales ADD PARTITION "4"
START('2014-04-01') INCLUSIVE
END ('2014-05-01') EXCLUSIVE ;
要查看分区表销售创建的表,你可以在PLSQL命令行使用命令\dt sales*。
要删除子分区模板,请使用带空圆括号SET SUBPARTITION模板。例如,清空销售表子分区模板:
ALTER TABLEsales SET SUBPARTITION TEMPLATE ();
更换一个叶子分区表和外部表
你可以将一个分区表的叶子分区和一个只读的外部表进行交换。外部表的数据可以是一个文件系统,NFS系统或HDFS。
例如,如果你有一个按月分区的表,并且大部分都是查询新数据,则你可以把那些旧的、很少方位的数据转移到外部表,并且使旧的分区和外部表进行数据交换。如果查询只需要访问最新的数,你可以在创建查询时忽略那些旧的、未使用的分区。
更换叶子分区与外部表不支持在这些情况下:
• 分区表在创建时使用了subparition 语法,或者这个分区含有子分区。
• 分区表的列有约束检查或者非空约束。
有关交流和改变叶子分区的信息,请参阅Greenplum的数据库命令参考ALTER TABLE命令。
有关包含外部表分区分区表的限制的信息,请参阅分区表的限制。
交换分区与外部表例子
这是一个简单的例子,这个交换分区表的外部表中的叶子分区。分区表包含了2000年至2003年的数据。
CREATE TABLE sales (id int, year int,qtr int, day int, region text)
DISTRIBUTED BY (id)
PARTITION BY RANGE (year)
( PARTITION yrSTART (2000) END (2004) EVERY (1) ) ;
这个分区表有四个叶子分区。每个叶子分区包含了一年的数据。叶子分区表sales_1_prt_yr_1包含了2000年的数据。采用gpfdist来交换sales_1_prt_yr_1和外部表的数据:
1. 首先确认外部表协议在GPDB数据库系统已启用。下面的例子演示如何使用gpfdist。执行如下命令来启动gpfdist。
$ gpfdist
2. 创建一个可写的外部表
这个CREATEWRITABLE外部TABLE命令创建具有相同的列分区表可写外部表。
CREATEWRITABLE EXTERNAL TABLE my_sales_ext ( LIKE sales_1_prt_yr_1 )
LOCATION ('gpfdist://gpdb_test/sales_2000' )
FORMAT'csv'
DISTRIBUTED BY (id) ;
3.创建一个只读外部表从前面步骤创建的可写外部表中读取数据。
此CREATEEXTENAL表创建使用相同的外部数据作为写入外部数据可读外部。
CREATE EXTERNAL TABLEsales_2000_ext ( LIKE sales_1_prt_yr_1)
LOCATION ('gpfdist://gpdb_test/sales_2000' )
FORMAT'csv' ;
4. 从叶子分区中的数据复制到可写的外部表。
这INSERT命令将文件从分区表的子分区叶表中的数据到外部表。
INSERTINTO my_sales_ext SELECT * FROM sales_1_prt_yr_1;
5.交换现有的叶子分区和外部表。
这ALTER TABLE命令指定EXCHANGEPARTITION子句来切换读取外部表和叶子分区。
ALTER TABLEsales ALTER PARTITION yr_1
EXCHANGEPARTITION yr_1
WITH TABLE sales_2000_ext WITHOUT VALIDATION;
这个外部表使用了表名sales_1_prt_yr_1并成为sales的叶子分区表。原来的叶子分区表变成了sales_2000_ext。
警告:为了确保对分区表的查询返回正确的结果,外部表中的数据必须是符合叶子分区的CHECK有效约束。在这种情况下,数据是从在其上定义的CHECK约束子叶分区表中获取。
6.删除从分区表移出来的表。
DROP TABLE sales_2000_ext ;
你可以重新命名叶子分区的名称,以表明sales_1_prt_yr_1 是一个外部表。
下面的命令将叶子分区重命名为yr_1_ext。
ALTER TABLEsales RENAME PARTITION yr_1 TO yr_1_ext ;
创建和使用序列
你可以使用序列来为一个表创建一个自增的唯一ID列。序列经常被用来为添加到表的数据分配唯一的识别号码。你可以声明一个列的数据类型为SERIAL以便隐式的声明和使用序列。
创建序列
createsequence命令创建并初始化一个命名为给定的序列名的特殊的单行序列发生器表。序列名必须唯一,不能和其他的序列、表、索引、视图等在同一个Schema内重复。例如
CREATE SEQUENCE myserial START 101;
使用序列
当你使用create sequence创建了一个序列生成器表之后,你就可以使用nextval来创建序列。例如,获取序列的下一个值并将数据插入到表中。
INSERT INTOvendors VALUES (nextval('myserial'), 'acme');
无法使用
ERROR: Interconnect Error: Could not connect toseqserver (connection: 11, host: 127.0.0.1, port: 14462). (seg0 slice1 tk-dat-asa213:40000 pid=145523)
DETAIL: Connection refused (connect errno 111)
**********错误**********
ERROR:Interconnect Error: Could not connect to seqserver (connection: 11, host:127.0.0.1, port: 14462). (seg0 slice1tk-dat-asa213:40000 pid=145523)
SQL状态:58M01
详细:Connectionrefused (connect errno 111)
你也可以使用setval函数来重置序列发生器的计数器,例如:
SELECTsetval('myserial', 201);
Nextval操作不会回滚。即使执行nextval的事务失败,一个获取的值被也认为是已使用。这就意味着失败的事务会留下未使用的序列空洞。setval 操作也不会回退。
需要注意的是,nextval操作在启用镜像后无法UPDATE和DELETE场景下使用,并且currval 和 lastval函数在GPDB中也不支持。
为了检测当前的序列设置,可以从序列表中查询。
SELECT * FROMmyserial;
更改序列
在ALTER SEQUENCE命令修改一个现有的序列发生器的参数。例如:
ALTER SEQUENCEmyserial RESTART WITH 105;
Any parametersnot set in the alter sequencecommand retain their prior settings.
删除序列
该DROP SEQUENCE命令删除一个序列生成器表。例如: DROP SEQUENCE myserial;
在Greenplum数据引擎使用索引
在大多传统的数据库,索引可以大大提高数据访问性能。然而,在分布式数据库如Greenplum的,索引应更谨慎使用。 Greenplum的数据库进行非常快的顺序扫描;索引使用随机寻求模式定位磁盘的记录。 Greenplum的数据在段分布,所以每个片段扫描整个数据的一小部分,以得到结果。使用表分区,扫描的总数据甚至可以更小。由于商业智能(BI)查询工作负载通常会返回非常大的数据集,使用索引的效率不高。
Greenplum建议在执行查询时无需设置索引。索引更可能改善OLTP工作负载,尤其是该查询返回单个记录或数据的一个小的子集的性能。索引也可以提高在压缩附加优化表的上返回有针对性的行集的查询上性能,因为优化器可以在适当的时候使用索引访问方法,而不是全表扫描。对于压缩数据,索引访问方法意味着只有必要的数据行进行解压缩。
Greenplum的数据库会为表的主键自动创建主键约束。要在一个分区表创建索引,那就在你创建的分区表上创建索引(To createan index on a partitioned table, create an index on the partitioned table thatyou created.英语怎么这样啰嗦)。创建您所创建的分区表的索引。该索引被传播到由Greenplum数据引擎创建的所有子表。在GPDB所创建的用于分区的表上创建索引不予支持(一个分区表,在后台创建若干表,在这些字表上创建索引不被支持)Creating anindex on a table that is created by Greenplum Database for use by a partitionedtable is not supported.。
请注意,唯一约束(如主键约束)隐式地创建唯一索引必须包含分发密钥的任何分区键的所有列。唯一约束是针对整个表执行的,包括所有的表分区(如果有的话)。
索引增加一些数据库的开销 - 他们使用的存储空间,当表被更新必须得到维护。确保查询工作负载使用您创建的索引,并检查是否添加索引提高查询性能(相对于表的顺序扫描)。要确定是否正在使用索引,检查查询EXPLAIN计划。请参阅查询剖析。
当你创建索引时考虑如下几点:
• 你的查询负载。。索引可以提高工作负荷,其中查询返回单个记录还是一个非常小的数据集,如OLTP工作负载的性能。
• 压缩表。索引可以提高对返回有针对性的行集的查询上压缩附加优化表的性能。对于压缩数据,索引访问方法意味着只有必要的行被解压缩。
• 避免在频繁更新的列上创建索引。在一个频繁更新的列上创建索引意味着当此列更新时增加了写工作量。
• 创建选择性的B树索引。索引选择性是一个列已经由行数表中的划分中不同值的数目的比率。例如,如果一个表有1000行和一列具有800不同的值,该指数的选择性为0.8,这被认为是良好的。唯一索引总是具有1.0的选择性比,这可能是最好的。Greenplum的数据库只允许在分布键列创建唯一索引。
• 对低的选择性列使用位图索引。在Greenplum数据位图索引类型不在普通的PostgreSQL提供。请参阅关于位图索引。
• 用于索引列连接。在用于频繁的一列的索引连接(如外键列),可提高使更多的连接方法的查询优化器使用连接性能。
• 索引列经常在谓词中使用。即在WHERE经常引用的列是创建索引的很好的候选者。
• 避免重复索引。具有相同的前导列索引是多余的。
• 在批量装载时删除索引。在向一个表导入大批数据时,考虑先删除索引,当导入完毕时再重新创建索引。这样会比更新索引更快速。
• 考虑创建一个聚类索引。聚类索引意味数据是根据索引的顺序进行物理存放的。如果你需要的记录在磁盘上随机存放,则数据库需要在磁盘上进行寻道以获取记录。如果数据存储在一起,则读取操作会更加有效。例如,在日期列的聚类索引,其中的数据顺序是按日期顺序存放。针对一个特定的日期范围的查询会导致一个有序的磁盘顺序读取,它利用快速顺序访问。
在Greenplum 上聚类一个索引
在一个非常大的表上使用cluster命令来使得数据按照索引重新排列是非常耗时的。为了更快的达到相同的目的,可以手动创建中间表,并将数据按照希望的顺序加载。例如:
CREATE TABLE new_table(LIKE old_table)
AS SELECT * FROM old_tableORDER BY myixcolumn;
DROP old_table;
ALTER TABLE new_tableRENAME TO old_table;
CREATE INDEX myixcolumn_ixON old_table;
VACUUM ANALYZE old_table;
索引类型
Greenplum的数据库支持Postgres的索引类型B树和GiST。哈希和GIN索引不支持。每个索引类型使用不同的算法,以适合于不同类型的查询。B树索引适合最常见的情况,而且默认的索引类型。见索引类型PostgreSQL文档以查看详细说明。
注意: Greenplum数据允许在Greenplum散列键的列相同(或超集)上创建唯一索引。唯一索引不支持附加优化表。对于分区表上,唯一索引无法跨分区表的所有子表分区执行。唯一索引是只在一个分区内支持。
关于位图索引
Greenplum的数据库提供的位图索引类型。位图索引是最适合于数据仓库应用程序和决策支持系统这种具有大量数据,许多即席查询,很少数据修改(DML)的事务。
索引提供了包含一个给定的键值的表指针的行。普通索引存储对应于与该键值的行每个键的元组ID列表。位图索引存储每个键值的位图。常规索引可以比在表中的数据大几倍,但位图索引提供相同的功能作为一个普通指标,并使用索引数据的大小的一小部分。
位图中的每一位对应一个可能的元组的ID。如果该位被设置,与对应的元组的ID的行中包含的关键值。映射函数转换比特位位置到元组ID。位图压缩采用存储。如果不同键值的数量是小的,位图索引小得多,压缩更好,并用常规的索引相比节省相当大的空间。位图索引的大小成比例的行表中的时间不同的值的索引列的数目。
位图索引是最有效的包含WHERE子句中的多个条件查询。满足了一些,但不是全部,条件过滤掉被访问表之前的行。这提高了响应性能,通常会非常显着。
何时使用位图索引
位图索引更适合于用户查询数据,而不是更新的数据仓库应用程序。位图索引在具有100至10万不同的值并且查询时经常和其他索引列进行联合查询时效果最佳。少于100个不同的值,例如与两个不同的值(男性和女性)性别列,任何类型的索引性能都不会太好。在有超过10万不同的值时,位图索引性能和空间效率会下降。
位图索引可以提高即席查询的查询性能。 AND和OR查询的WHERE子句中的条件可以通过转换生成位图到元组IDS前直接对位图进行相应的布尔运算快速解决。如果得到的行数小,查询可以很快地回答,而不诉诸全表扫描。
何时不使用位图索引
(适合B树索引的地方,唯一列或列的高基数数据,如客户名称或电话号码),不要使用位图索引。无论表中数据行数有多少,当唯一的键值超过10万时,位图索引的性能和磁盘空间优势就会下降。
位图索引不适合有大量修改数据的并发事务的OLTP应用程序。
使用位图索引谨慎。测试和使用和不使用索引比较查询性能。仅对添加索引后查询性能有提升的列添加位图索引。
创建索引
CREATE INDEX命令定义表的索引。 A B树索引是默认索引类型。例如,要创建对表中的雇员列性别的B树索引:
CREATE INDEXgender_idx ON employee (gender);
要在films表的title列创建位图索引:
CREATE INDEX title_bmp_idxON films USING bitmap (title);
检查索引使用
Greenplum的数据库索引并不需要维护和调整。您可以检查哪些指标是由真实的查询工作负载中使用。使用EXPLAIN命令检查查询索引使用。
查询计划会显示数据库对每个查询节点需要的耗时。要检查索引的使用,请在您的EXPLAIN输出下面的查询计划节点类型:
The query plan shows the steps or plan nodes that thedatabase will take to answer a query and time estimates for each plan node. Toexamine the use of indexes, look for the following query plan node types in your explain output:
• Index Scan –对索引的扫描.
• Bitmap HeapScan -从BitmapAnd,BitmapOr或BitmapIndexScan生成位图的所有检索和访问堆检索相关行。
• Bitmap IndexScan -通过的OR-ing满足查询从标的指数的谓词所有位图计算的位图。Compute a bitmap by OR-ing all bitmapsthat satisfy the query predicates from the underlying index.
• BitmapAnd orBitmapOr -注意到从多个BitmapIndexScan节点与运算或OR值在一起所产生的位图,并生成一个新的位图作为其输出。 Takes the bitmaps generated from multipleBitmapIndexScan nodes, ANDs or ORs them together, and generates a new bitmap asits output.
你必须实验,以确定索引创建。考虑以下几点。
• 您创建或更新索引后运行analyze 。ANALYZE收集表统计信息。查询优化器使用表统计信息来估计查询返回的行数和分配的现实成本,每个可能的查询计划。
• 用于实验使用真实数据。使用测试数据建立索引的告诉你,你需要对测试数据有什么指标,但仅此而已。
• 不要使用非常小的测试数据集作为其结果可能是不现实的或倾斜。
• 开发测试数据时要小心。相似的,完全随机的,顺序插入的数据会是的统计信息偏离真实的数据统计分布状态。
• 你可以通过运行时参数强制关闭特定类型的计划类型来进行测试。例如, 关闭顺序扫描 (enable seqscan) 和nested-loopjoins (enable nested-loop), 最基本的计划等。通过使用和不使用索引的时间查询并使用EXPLAIN ANALYZE命令来比较的结果。
管理索引
使用REINDEX命令重建效果不佳的指标。 REINDEX重建使用存储在索引表中的数据的索引,取代的索引的旧副本。.
To rebuild all indexes on a table
REINDEXmy_table;
To rebuild a particular index
REINDEXmy_index;
Dropping an Index
drop index命令会删除所有的索引,例如:
DROP INDEXtitle_idx;
在加载数据时,先删除索引,加载数据,再重新创建索引会更快。
创建和管理视图
视图使您可以将常用的或复杂的查询,然后访问它们在SELECT语句中,好像他们是一个表。视图是没有实际物化在磁盘上:当您访问视图时,后台就运行了子查询。
如果子查询与单个查询相关联,可以考虑使用SELECT命令的WITH子句,而不是创建一个很少使用的视图。
创建视图
create view定义一个视图的 查询. 例如:
CREATE VIEWcomedies AS SELECT * FROM films WHERE kind = 'comedy';
Views ignore order by and sort operations storedin the view.
删除视图
drop view命令删除一个视图,例如:
DROPVIEW topten;