基于 SQL 视图创建的图表概览

本文档介绍了使用 SQL 视图创建图表的优势。本文档介绍了使用视图创建图表的优势要求注意事项,可帮助您确定是应使用还是视图来创建图表。

如需详细了解如何从视图创建图,请参阅从 SQL 视图创建属性图

使用视图而非表格创建图表的好处

SQL 视图是由 SQL 查询定义的虚拟表。在 Spanner 中,每次执行引用视图的查询时,都会执行定义视图的查询。Spanner 视图不是物化视图,因为它们不会将定义视图的查询结果存储为数据存储空间中的实际表。如需了解详情,请参阅视图概览。您可以从 SQL 视图创建图元素,但无法创建查询图的视图。

作为表和图架构之间的抽象层,视图具有多项优势,而使用表创建图时无法获得这些优势。

使用视图创建图表的要求

使用视图创建图元素时,您必须遵循以下要求:

指定图元素时,请使用 KEY 子句

使用视图创建节点或边元素时,您必须明确定义唯一标识图表元素的列。为此,请在节点或边元素定义中使用 KEY 子句。如需了解如何在创建图元素时使用 KEY 子句,请参阅本文档和从 SQL 视图创建 Spanner Graph 中的代码示例。

使用可确保节点和边具有唯一性的视图

定义节点或边表的视图必须遵循以下模式之一,以确保节点和边的唯一性:

  • 模式 1:视图使用单个表的主键。

  • 模式 2:视图使用 GROUP BYSELECT DISTINCT 子句。

您可以将其他 SQL 运算符(例如 WHEREHAVINGORDER BYLIMITTABLESAMPLE)与这些模式结合使用。这些运算符会过滤或排序结果,但不会更改模式提供的底层唯一性保证。

模式 1:使用单个表的主键

在此模式中,视图从单个表中进行选择,并且图定义中的 KEY 子句与基表的主键列相匹配。因此,视图生成的每个节点或边行都是唯一的。

例如,以下查询从 Account 表中选择部分行。图 KEY(account_id)Account 表的主键匹配,这可确保视图生成的每一行都是唯一的。

-- Table has PRIMARY KEY(account_id).
CREATE TABLE Account (
  account_id INT64 NOT NULL,
  customer_id INT64 NOT NULL,
  account_type STRING(MAX),
  balance INT64
) PRIMARY KEY(account_id);

-- Pattern 1: View uses the primary key from a single table.
CREATE VIEW SavingAccount
  SQL SECURITY INVOKER AS
    SELECT accnt.account_id, accnt.customer_id, accnt.balance
    FROM Account accnt
    WHERE accnt.account_type = 'saving';

CREATE PROPERTY GRAPH SavingAccountGraph
  NODE TABLES (
    -- The element KEY(account_id) matches the table's primary key.
    SavingAccount KEY(account_id)
  );

模式 2:使用 GROUP BYSELECT DISTINCT 子句

在此模式中,视图的查询使用 GROUP BYSELECT DISTINCT 子句。KEY 子句中的列必须与这些子句用于定义唯一性的列相匹配:

  • 对于 GROUP BYKEY 子句列必须与 GROUP BY 子句中的所有列匹配。

  • 对于 SELECT DISTINCTKEY 子句列必须与 SELECT DISTINCT 列表中的列相匹配。

GROUP BY”出价策略示例:

CREATE TABLE Customer (
  customer_id INT64,
  name STRING(MAX)
) PRIMARY KEY (customer_id);

CREATE TABLE SaleOrder (
  order_id INT64,
  customer_id INT64,
  amount INT64
) PRIMARY KEY (order_id);

CREATE VIEW CustomerOrder
  SQL SECURITY INVOKER AS
    SELECT
      s.order_id,
      ANY_VALUE(c.customer_id) AS customer_id,
      ANY_VALUE(c.name) AS customer_name
    FROM Customer c JOIN SaleOrder s ON c.customer_id = s.customer_id
    GROUP BY s.order_id;

CREATE PROPERTY GRAPH OrderGraph
  NODE TABLES (
    -- The KEY(order_id) matches the GROUP BY column in view definition.
    CustomerOrder KEY(order_id)
  );

SELECT DISTINCT”出价策略示例:

CREATE TABLE SaleOrder (
  order_id INT64,
  customer_id INT64,
  amount INT64
) PRIMARY KEY (order_id);

CREATE VIEW KeyCustomer SQL SECURITY INVOKER AS
  SELECT DISTINCT s.customer_id, s.amount
  FROM SaleOrder s
  WHERE s.amount > 1000;

CREATE PROPERTY GRAPH KeyCustomersGraph
  NODE TABLES (
    -- The KEY(customer_id, amount) matches the DISTINCT columns.
    KeyCustomer KEY(customer_id, amount)
  );

使用视图时的注意事项

使用视图定义图元素时,以下内容可帮助您设计和实现有效的图:

属性图表查询性能

在执行数据转换的视图(例如 GROUP BYUNNESTJOIN 操作)上定义图元素时,请仔细评估您的使用情形的查询性能。请注意,每次查询执行元素模式匹配时,Spanner 都会执行视图的查询定义。

图架构优化

使用视图定义图元素时,某些图架构优化可能不如使用表定义图元素时有效。

投影单个表的主键的视图

如果视图是单个基表的投影,则对该底层表进行的任何优化对图查询仍然有效。例如,对基表应用以下技术可为基于此类视图定义的图元素带来类似的性能优势:

使用 GROUP BYDISTINCT 子句定义的视图

执行聚合的视图(例如 GROUP BYSELECT DISTINCT 或其他复杂转换)会失去与底层表结构的直接关系。因此,对基表进行的架构优化可能无法为对视图执行的图查询带来相同的性能优势。当视图执行复杂的聚合时,请仔细评估您的使用情形的查询性能。

使用基于视图的图表修改数据

视图不是具体化的,这意味着它们不会将定义视图的查询结果作为表存储在数据存储空间中,并且是只读的。因此,如需在通过视图创建的图表中插入、更新或删除节点或边,您需要修改用于创建视图的表中的数据。

图表错误处理,以确保数据完整性

使用视图定义图元素时,请对底层基本表强制执行数据完整性(例如,强制执行数据类型)。否则,基表中的数据可能无效,并导致基于视图的图表的查询在运行时失败。

例如,当您从无架构过渡到正式的图时,请使用 CHECK 限制条件来验证基本表(GraphNodeGraphEdge)中的数据。以下代码在 JSON 属性中应用这些限制条件,以确保源端的数据完整性并防止运行时查询错误。

-- Enforce that the 'name' property exists for nodes with the 'person' label.
ALTER TABLE GraphNode
ADD CONSTRAINT NameMustExistForPersonConstraint
CHECK (IF(label = 'person', properties.name IS NOT NULL, TRUE));

-- Enforce that the 'name' property is a string for nodes with the 'person' label.
ALTER TABLE GraphNode
ADD CONSTRAINT PersonNameMustBeStringTypeConstraint
CHECK (IF(label = 'person', JSON_TYPE(properties.name) = 'string', TRUE));

后续步骤