这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

创建自定义设计

Vertica 强烈建议您使用由 Database Designer 生成的物理架构设计,因为该软件可提供 K-safety、卓越的查询性能以及存储空间的有效使用。如果任何查询未能按照预期高效运行,可考虑使用 Database Designer 增量设计流程来优化该查询的数据库设计。

如果 Database Designer 创建的投影仍然不能满足您的需求,您可以从头开始或者根据 Database Designer 创建的投影设计来编写自定义投影。

如果您不熟悉如何编写自定义投影,可以从修改 Database Designer 生成的现有设计开始入手。

1 - 自定义设计流程

要创建自定义设计或自定义现有设计:

  1. 规划新的设计或修改现有设计。请参阅规划您的设计

  2. 创建或修改投影。有关详细信息,请参阅设计基础知识CREATE PROJECTION

  3. 将投影部署到一个测试环境。请参阅写入并部署自定义投影

  4. 根据需要测试并修改投影。

  5. 敲定设计后,将投影部署到生产环境。

2 - 规划您的设计

对于熟悉 SQL 的任何人来说,用于创建设计的语法是非常简单的。然而,对于任何成功的项目而言,成功的设计需要一些初始规划。在创建第一个设计前:

  • 熟悉标准设计要求并将您的设计规划为包括这些要求。请参阅设计要求

  • 确定您需要将多少个投影包括在设计中。请参阅确定要使用的投影数量

  • 确定要用于列的压缩和编码类型。请参阅体系结构

  • 确定是否希望数据库具有 K-safe。Vertica 建议所有生产数据库都应至少将 K-safety 设置为 1 (K=1)。有效的 K-safe 值为 0、1 和 2。请参阅K-safety 设计

2.1 - 设计要求

物理架构设计是包含 CREATE PROJECTION 语句的脚本。这些语句确定包括在投影中的列及其优化方式。

如果您开始时使用 Database Designer,它将自动创建满足所有基础设计要求的设计。如果您打算手动创建或修改设计,请注意所有设计必须满足以下要求:

  • 对于客户端应用程序所使用的数据库中的每个表,每个设计必须至少为其创建一个超投影。这些投影提供全面覆盖,用户可利用该覆盖范围根据需要执行临时查询。它们可以包含联接,而且通常被配置为通过排序顺序、压缩和编码最大限度提高性能。

  • 查询特定的投影为可选项。如果您对超投影所提供的性能满意,则无需创建其他投影。但是,可通过优化特定查询工作负载来最大限度提高性能。

  • Vertica 建议所有生产数据库都应至少将 K-safety 设置为一 (K=1) 以支持高可用性和高恢复性。(K-safety 可以设置为 0、1 或 2。)请参阅使用投影的高可用性K-safety 设计

  • 如果节点数超过 20 但表为小型表,Vertica 建议您不要创建复制的投影。如果创建复制的投影,编录会变得非常大,而且性能可能会降低。相反,请考虑对这些投影分段。

2.2 - 确定要使用的投影数量

在许多情况下,由一组超投影(及其伙伴实例)组成的设计可通过压缩和编码提供令人满意的性能。当已使用投影的排序顺序最大限度提高一个或多个查询谓语(WHERE 子句)的性能时,情况尤其如此。

但是,您可能希望添加其他查询特定投影以提高运行缓慢、经常使用或作为业务关键报告的一部分运行的查询的性能。您创建的其他投影(及其伙伴实例)的数量应由以下项目决定:

  • 组织需求

  • 群集中每个节点上的可用磁盘空间量

  • 将数据加载到数据库中的可用时间量

随着针对特定查询而优化的投影数量的增加,这些查询的性能得到提高。但是,已用磁盘空间量和加载数据所需的时间量也会增加。因此,应创建和测试设计以确定您的数据库配置的最佳投影数量。平均而言,选择实施查询特定投影的组织可通过添加几个查询特定投影来实现最佳性能。

2.3 - K-safety 设计

Vertica 建议所有生产数据库都应至少将 K-safety 设置为 1 (K=1)。生产数据库的有效 K-safety 值为 1 和 2。非生产数据库不必为 K-safe,可将该值设置为 0。

K-safe 数据库必须至少包含三个节点,如下表所示:

1
3+
2
5+

仅当物理架构设计满足某些冗余要求时,才能将 K-safety 设置为 1 或 2。请参阅K-safe 物理架构设计的要求

使用 Database Designer

要创建具有 K-safe 状态的设计,Vertica 建议您使用 Database Designer。使用 Database Designer 创建投影时,建议使用满足 K-safe 设计要求的投影定义并用 K-safety 级别加以标记。Database Designer 会创建一个脚本,该脚本使用 MARK_DESIGN_KSAFE 函数将物理架构的 K-safety 设置为 1。例如:

=> \i VMart_Schema_design_opt_1.sql
CREATE PROJECTION
CREATE PROJECTION
mark_design_ksafe
----------------------
Marked design 1-safe
(1 row)

默认情况下,当数据库的 K-safety 大于 0 时,Vertica 会创建 K-safe 超投影。

监控 K-safety

监控表可以通过编程方式访问,以启用外部操作,例如警报。通过查询 SYSTEM 表内 DESIGNED_FAULT_TOLERANCECURRENT_FAULT_TOLERANCE 列中的设置,可以监控 K-safety 级别。

K-safety 丢失

当群集中的 K 个节点出现故障时,数据库将继续运行,但性能会受到影响。如果故障节点的数据无法从群集中另一个正常工作的节点中获取,那么后续节点故障可能会导致数据库关闭。

另请参阅

企业模式数据库中的 K-safety

2.3.1 - K-safe 物理架构设计的要求

Database Designer 使用值为 1 的 K-safety 为至少包含三个节点的群集自动生成设计。(如果群集具有一个或两个节点,它将使用值为 0 的 K-safety 生成设计。)您可以修改为三节点(或更大)群集创建的设计,而且 K-safe 要求已设置完毕。

如果您创建自定义投影,物理架构设计必须满足以下要求才能在出现故障时成功恢复数据库:

可使用 MARK_DESIGN_KSAFE 函数确定您的架构设计是否满足 K-safety 的要求。

2.3.2 - 无 K-safety 的物理架构设计的要求

如果您使用 Database Designer 生成一个您可以修改的全面设计并且您不希望设计具有 K-safe,请将 K-safety 级别设置为 0(零)。

如果您想要从头开始,请执行以下操作为一个不具有 K-safety (K=0) 的有效数据库建立最低投影要求:

  1. 逻辑架构中的每个表至少定义一个 超投影

  2. 复制(定义一个完全相同的副本)每个 节点上的每个维度表超投影。

2.3.3 - 为 K-safety 安全设计分段投影

投影必须符合数据库 K-safety 要求。通常,您必须为每个分段投影创建伙伴实例投影,其中伙伴实例投影的数量为 K+1。因此,如果系统 K-safety 设置为 1,则必须通过一个伙伴实例复制每个投影分段;如果 K-safety 设置为 2,则必须通过两个伙伴实例复制每个分段。

自动创建伙伴实例投影

通过包括 SEGMENTED BY ... ALL NODES,可以使用 CREATE PROJECTION 自动创建满足 K-safety 所需的伙伴实例投影数量。如果 CREATE PROJECTION 指定 K-safety ( KSAFE=n),Vertica 将使用该设置;如果语句省略 KSAFE,Vertica 将使用系统 K-safety。

在以下示例中,CREATE PROJECTION 为表 ttt 创建分段投影 ttt_p1。由于系统 K‑safety 设置为 1,因此 Vertica 需要每个分段投影拥有一个伙伴实例投影。由于“CREATE PROJECTION”语句省略“KSAFE”,因此 Vertica 使用系统 K‑safety 并创建两个伙伴实例投影:“ttt_p1_b0”和“ttt_p1_b1”:

=> SELECT mark_design_ksafe(1);

  mark_design_ksafe
----------------------
 Marked design 1-safe
(1 row)

=> CREATE TABLE ttt (a int, b int);
WARNING 6978:  Table "ttt" will include privileges from schema "public"
CREATE TABLE

=> CREATE PROJECTION ttt_p1 as SELECT * FROM ttt SEGMENTED BY HASH(a) ALL NODES;
CREATE PROJECTION

=> SELECT projection_name from projections WHERE anchor_table_name='ttt';
 projection_name
-----------------
 ttt_p1_b0
 ttt_p1_b1
(2 rows)

通过将后缀 _bn 附加到投影基本名(例如 ttt_p1_b0),Vertica 自动为伙伴实例投影命名。

手动创建伙伴实例投影

如果在单个节点上创建投影并且系统 K-safety 大于 0,则必须手动创建 K-safety 所需的伙伴实例数量。例如,可以在单个节点上为表 xxx 创建投影 xxx_p1,如下所示:

=> CREATE TABLE xxx (a int, b int);
WARNING 6978:  Table "xxx" will include privileges from schema "public"
CREATE TABLE

=> CREATE PROJECTION xxx_p1 AS SELECT * FROM xxx SEGMENTED BY HASH(a) NODES v_vmart_node0001;
CREATE PROJECTION

由于 K-safety 设置为 1,此投影的单个实例不是 K-safe。若尝试将数据插入到它的锚表 xxx,则会返回如下错误:

=> INSERT INTO xxx VALUES (1, 2);
ERROR 3586:  Insufficient projections to answer query
DETAIL:  No projections that satisfy K-safety found for table xxx
HINT:  Define buddy projections for table xxx

为了符合 K-safety,您必须为投影 xxx_p1 创建一个伙伴实例投影。例如:

=> CREATE PROJECTION xxx_p1_buddy AS SELECT * FROM xxx SEGMENTED BY HASH(a) NODES v_vmart_node0002;
CREATE PROJECTION

xxx 现在符合 K-safety 并接受 DML 语句(例如 INSERT):

VMart=> INSERT INTO xxx VALUES (1, 2);
 OUTPUT
--------
      1
(1 row)

另请参阅

有关分段投影和伙伴实例的一般信息,请参阅分段投影。有关 K-safety 设计的信息,请参阅K-safety 设计分段设计

2.3.4 - 为 K‑Safety 设计未分段投影

在许多情况下,维度表相对较小,因此您无需将它们分段。相应地,您应该设计一个 K-safe 数据库,以便可以复制其维度表的投影并且无需在所有群集节点上进行分段。您可以使用包括关键字 UNSEGMENTED ALL NODESCREATE PROJECTION 语句创建这些投影。这些关键字用于指定在所有群集节点上创建投影的相同实例。

以下示例展示了如何为表 store.store_dimension 创建未分段投影:


=> CREATE PROJECTION store.store_dimension_proj (storekey, name, city, state)
             AS SELECT store_key, store_name, store_city, store_state
             FROM store.store_dimension
             UNSEGMENTED ALL NODES;
CREATE PROJECTION

Vertica 使用相同的名称来标识未分段投影的所有实例 — 在此示例中为 store.store_dimension_proj。关键字 ALL NODES 指定在所有节点上复制投影:


=> \dj store.store_dimension_proj
                         List of projections
 Schema |         Name         |  Owner  |       Node       | Comment
--------+----------------------+---------+------------------+---------
 store  | store_dimension_proj | dbadmin | v_vmart_node0001 |
 store  | store_dimension_proj | dbadmin | v_vmart_node0002 |
 store  | store_dimension_proj | dbadmin | v_vmart_node0003 |
(3 rows)

有关投影名称约定的详细信息,请参阅投影命名

2.4 - 分段设计

可使用哈希分段对投影分段。哈希分段可基于内置的哈希函数对投影进行分段。该内置哈希函数可使多个节点中的数据实现正态分布,从而优化查询的执行。在投影中,要进行哈希的数据由一列或多列值组成,每一列都包含大量唯一值,并且值的分布偏移程度在可接受的范围内。满足标准的主键列非常适合进行哈希分段。

分段投影时,确定哪些列用于对投影分段。选择具有大量唯一数据值和在数据分布中可接受的偏离的一个或多个列。主键列是哈希分段的绝佳选择。这些列在查询中所用的所有表上必须唯一。

3 - 设计基础知识

尽管您可以从头开始编写自定义投影,但 Vertica 建议您使用 Database Designer 创建设计来作为起点。这样可确保您获得满足基本要求的投影。

3.1 - 写入并部署自定义投影

在编写自定义投影之前,请仔细查看规划您的设计中的主题。不遵循这些注意事项可能会生成无法正常工作的投影。

要手动修改或创建投影:

  1. 使用 CREATE PROJECTION 语句编写脚本以创建所需的投影。

  2. 使用元命令 \i 在 vsql 中运行脚本。

  3. 对于 K-safe 数据库,调用 Vertica 元函数 GET_PROJECTIONS 在新预测表上。检查输出,验证所有投影是否有足够的伙伴被识别为安全。

  4. 如果您为已包含数据的表创建投影,请调用 REFRESHSTART_REFRESH 更新新投影。否则,这些投影不可用于查询处理。

  5. 调用 MAKE_AHM_NOW,将 Ancient History Mark (AHM) 设置为最近的时期。

  6. 对于不再需要的投影,请调用 DROP PROJECTION,否则将浪费磁盘空间并降低加载速度。

  7. 对于所有数据库投影,请调用 ANALYZE_STATISTICS

    => SELECT ANALYZE_STATISTICS ('');
    

    此函数从用于存储投影的所有节点中收集和聚合数据样本及存储信息,然后将统计信息写入到编录中。

3.2 - 设计超级投影

超投影需要满足以下要求:

  • 它们必须包含表中的每个列。

  • 对于 K-safe 设计,必须在数据库群集内的所有节点上复制超投影(适用于维度表),或者与伙伴投影进行配对并跨越所有节点进行分段(适用于很大的表和中等的表)。有关投影及其存储方式的概述,请参阅投影使用投影的高可用性。有关设计细节,请参阅K-safety 设计

要实现最大可用性,超投影需要最大限度降低存储要求,同时最大限度提升查询性能。为了实现这一目标,超投影中列的排序顺序以存储要求和常用查询为基础。

3.3 - 排序顺序的优势

列排序顺序是将存储空间要求降至最低和最大限度提高查询性能的重要因素。

将存储空间要求降至最低

最小化存储不但可以节省物理资源,而且还可以减少磁盘 I/O,以显著提高性能。通过在排序顺序中优先考虑低基数列,可以最大程度地减少投影存储。这会减少 Vertica 检索查询结果时所存储和访问的行数。

确定投影排序列后,分析其数据并选择效率最高的编码方法。Vertica 优化器使用运行长度编码 (RLE) 为列提供首选项,因此请确保在适当的情况下使用它。运行长度编码将相同值的序列(运行)替换为包含值和出现次数的单个对。因此,它特别适合用于运行长度较大的低基数列。

最大限度提高查询性能

可通过列排序顺序提高查询性能,方法如下:

  • 排序顺序应尽可能地使用最低基数确定列的优先级。

  • 请勿在 LONG VARBINARY 和 LONG VARCHAR 类型的列上排序投影。

另请参阅

选择排序顺序:最佳实践

3.4 - 选择排序顺序:最佳实践

选择投影的排序顺序时,Vertica 具有多条建议,可以帮助您实现最大查询性能,如以下示例中所示。

组合使用 RLE 和排序顺序

当处理低基数列中的谓词时,组合使用 RLE 和排序可最大程度减少存储要求,同时实现最大查询性能。

假设您具有一个包含以下值和编码类型的 students 表:

您可能具有类似如下所示的查询:

SELECT name FROM studentsWHERE gender = 'M' AND pass_fail = 'P' AND class = 'senior';

最快的数据访问方式是先处理非重复值数量最少的低基数列,然后再处理高基数列。对于对 genderclasspass_failname 具有相同限制的查询,以下排序顺序可最大程度减少存储要求,同时实现最大查询性能。如下所示指定投影的 ORDER BY 子句:

ORDER BY students.gender, students.pass_fail, students.class, students.name

在本示例中,gender 列由两个 RLE 条目表示,pass_fail 列由四个条目表示,而 class 列由 16 个条目表示,而不考虑 students 表的基数。Vertica 可有效地查找一组满足所有谓词的行,从而大幅减少了在排序顺序早期出现的 RLE 编码列搜索工作。因此,如果您在局部谓词中使用低基数列(如上例所示),请尽早将这些列按照非重复基数的递增顺序(即按照每列中非重复值数量的递增顺序)放入投影排序顺序中。

如果先使用 student.class 排序此表,则可以提高仅对 student.class 列存在限制的查询的性能,并改善 student.class 列(包含非重复值数量最多的列)的压缩性能,但其他列也不会压缩。确定哪个投影更好取决于工作负载中的特定查询及其相对重要性。

随着列基数的增加,通过压缩节省的存储空间会降低;但是,随着在该列中存储值所需字节数的增加,通过压缩节省的存储空间也会增加。

充分发挥 RLE 优势

为了充分发挥 RLE 编码的优势,请仅在列的平均运行长度大于 10(排序时)时使用该编码。例如,假设您具有包含以下列的表,各列按基数由低到高的顺序排列:

address.country, address.region, address.state, address.city, address.zipcode

zipcode 列可能在具有相同 zip 代码的行中没有 10 个排序条目,因此对该列执行运行长度编码很可能没有优势,而且可能会导致压缩性能变差。但在排序的运行长度中可能有超过 10 个国家/地区,因此对该国家/地区列应用 RLE 可以提高性能。

先放置基数较低的列以实现函数依赖项

一般而言,在联接顺序中先放置用于局部谓词(如上例所示)的列可使谓词求值更加高效。另外,如果通过基数较高的列来唯一确定基数较低的列(如仅 city_id 唯一确定 state_id),则在排序顺序中先放置基数较低、通过函数确定的列总比先放置基数较高的列好。

例如,在以下排序顺序中,customer_info 表中的 Area_Code 列排在 Number 列之前。

ORDER BY = customer_info.Area_Code, customer_info.Number, customer_info.Address

在查询中,先放置 Area_Code 列,以便仅扫描 Number 列中以 978 开头的值。

=> SELECT AddressFROM customer_info WHERE Area_Code='978' AND Number='9780123457';

合并联接排序

处理联接时,Vertica 优化器会从两种算法中进行选择:

  • 合并联接 — 如果两个输入都按联接列预先排序,优化器会选择合并联接,因为这种算法更快而且使用的内存更少。

  • 哈希联接 — 利用哈希联接算法,Vertica 会使用较小的(内部)联结表在内存中构建联接列的哈希表。哈希联接没有排序要求,但却会消耗更多内存,因为 Vertica 会构建一个包含内部表值的哈希表。如果投影未存储在联接列上,则优化器会选择一种哈希联接。

如果两个输入都预先排序,合并联接不必执行任何预处理,因而可以更快地执行联接。Vertica 使用的术语“排序-合并联接”是指在合并联接之前必须对至少一个输入排序的情况。只有当外部输入端已按联接列排序时,Vertica 才会排序内部输入端。

为了使 Vertica 查询优化器能够为特定联接选择使用有效的合并联接,请在联接的两端创建投影,并在相应投影中先放置联接列。如果两个表都非常大,内存中无法容纳任何一个表,那么这样做将非常重要。如果预期内存中可以同时容纳某个表要联接到的所有表,那么合并联接的优势比哈希联接要小很多,很可能并不值得为任何一个联接列创建投影。

在重要查询中按列排序

如果您有一个重要查询,并且您会定期运行该查询,那么将该查询 WHERE 子句或 GROUP BY 子句中指定的列先放入排序顺序中可以为您节省时间。

如果该查询使用高基数列(如社会保险号),则将该列先放入投影的排序顺序中可能会牺牲存储空间,但您的最重要查询将得到优化。

按大小排序基数相等的列

如果有两个基数相等的列,则在排序顺序中先放置较大的列。例如,CHAR(20) 列占用 20 字节,但 INTEGER 列占用 8 字节。通过将 CHAR(20) 列放在 INTEGER 列前面,可以更好地压缩投影。

按非重复基数由低到高的顺序,先排序外键列

假设您有一个事实表,排序顺序中的前四列组成了另一个表的外键。为了获得最佳压缩效果,我们为事实表选择一个排序顺序,使其先显示外键,并以非重复基数的递增顺序排列。在设计事实表的投影时,还可应用其他因素,如按时间维度(若存在)分区。

在以下示例中,表 inventory 用于存储库存数据,product_keywarehouse_keyproduct_dimensionwarehouse_dimension 表的外键:

=> CREATE TABLE inventory (
 date_key INTEGER NOT NULL,
 product_key INTEGER NOT NULL,
 warehouse_key INTEGER NOT NULL,
 ...
);
=> ALTER TABLE inventory
   ADD CONSTRAINT fk_inventory_warehouse FOREIGN KEY(warehouse_key)
   REFERENCES warehouse_dimension(warehouse_key);
ALTER TABLE inventory
   ADD CONSTRAINT fk_inventory_product FOREIGN KEY(product_key)
   REFERENCES product_dimension(product_key);

库存表应当先按 warehouse_key 排序,然后再按 product_key 排序,因为 warehouse_key 列的基数很可能低于 product_key 的基数。

3.5 - 确定列访问速度的优先级

如果您测量和设置群集内的存储位置的性能,Vertica 将使用此信息确定在哪里基于列的排名来存储列。有关详细信息,请参阅设置存储性能

如何对列排名

Vertica 将投影排序顺序中包含的列存储在最快的可用存储位置。未包含在投影排序顺序中的列将存储在稍慢的磁盘中。每个投影的列按如下方式排序:

  • 排序顺序中的列具有最高优先级(编号 >1000)。

  • 排序顺序中最后一列的排序编号为 1001。

  • 排序顺序中倒数第二的列排序编号为 1002,以此类推,直到排序顺序中的第一列,其排序编号为 1000 + 排序列数。

  • 剩余列的排序编号在 1000–1 之间,从 1000 开始,每列减一。

Vertica 随后将列从最高排号到最低排号存储在磁盘中。它将最高排号的列放在最快的磁盘上,将最低排号的列放在最慢的磁盘上。

覆盖默认列排名

通过手动覆盖这些列的默认排名,您可以修改将哪些列存储在快速磁盘上。要完成此操作,请设置列列表中的 ACCESSRANK 关键字。确保使用一个当前尚未用于另一个列的整数。例如,如果您要为某列提供最快速的访问排名,可使用一个明显高于 1000 + 排序列数量之和的数字。这样一来,您便可以随着时间的推移输入更多列,而不会跌入到您设置的访问排名中。

以下示例将列 store_key 的访问等级设置为 1500:

CREATE PROJECTION retail_sales_fact_p (
     store_key ENCODING RLE ACCESSRANK 1500,
     pos_transaction_number ENCODING RLE,
     sales_dollar_amount,
     cost_dollar_amount )
AS SELECT
     store_key,
     pos_transaction_number,
     sales_dollar_amount,
     cost_dollar_amount
FROM store.store_sales_fact
ORDER BY store_key
SEGMENTED BY HASH(pos_transaction_number) ALL NODES;