本文档介绍了使用 SQL 视图创建图表的优势。本文档介绍了使用视图创建图表的优势、要求和注意事项,可帮助您确定是应使用表还是视图来创建图表。
如需详细了解如何从视图创建图,请参阅从 SQL 视图创建属性图。
使用视图而非表格创建图表的好处
SQL 视图是由 SQL 查询定义的虚拟表。在 Spanner 中,每次执行引用视图的查询时,都会执行定义视图的查询。Spanner 视图不是物化视图,因为它们不会将定义视图的查询结果存储为数据存储空间中的实际表。如需了解详情,请参阅视图概览。您可以从 SQL 视图创建图元素,但无法创建查询图的视图。
作为表和图架构之间的抽象层,视图具有多项优势,而使用表创建图时无法获得这些优势。
行级访问权限控制。 使用定义方权限视图的安全权限,在行级层面对图数据应用精细访问权限控制。这样可确保用户只能查询他们有权查看的节点和边。
灵活的数据建模。 在创建图元素之前,使用包含查询的视图来调整和转换关系数据。通过视图的查询,您可以过滤行、合并列或取消嵌套重复字段(如
ARRAY中所示)。从无架构数据过渡到正式数据。 从无架构数据创建视图,以明确定义节点和边类型。这有助于规范数据中的关系。
使用视图创建图表的要求
使用视图创建图元素时,您必须遵循以下要求:
指定图元素时,请使用 KEY 子句
使用视图创建节点或边元素时,您必须明确定义唯一标识图表元素的列。为此,请在节点或边元素定义中使用 KEY 子句。如需了解如何在创建图元素时使用 KEY 子句,请参阅本文档和从 SQL 视图创建 Spanner Graph 中的代码示例。
使用可确保节点和边具有唯一性的视图
定义节点或边表的视图必须遵循以下模式之一,以确保节点和边的唯一性:
您可以将其他 SQL 运算符(例如 WHERE、HAVING、ORDER BY、LIMIT 和 TABLESAMPLE)与这些模式结合使用。这些运算符会过滤或排序结果,但不会更改模式提供的底层唯一性保证。
模式 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 BY 或 SELECT DISTINCT 子句
在此模式中,视图的查询使用 GROUP BY 或 SELECT DISTINCT 子句。KEY 子句中的列必须与这些子句用于定义唯一性的列相匹配:
对于
GROUP BY:KEY子句列必须与GROUP BY子句中的所有列匹配。对于
SELECT DISTINCT:KEY子句列必须与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 BY、UNNEST 或 JOIN 操作)上定义图元素时,请仔细评估您的使用情形的查询性能。请注意,每次查询执行元素模式匹配时,Spanner 都会执行视图的查询定义。
图架构优化
使用视图定义图元素时,某些图架构优化可能不如使用表定义图元素时有效。
投影单个表的主键的视图
如果视图是单个基表的投影,则对该底层表进行的任何优化对图查询仍然有效。例如,对基表应用以下技术可为基于此类视图定义的图元素带来类似的性能优势:
使用 GROUP BY 或 DISTINCT 子句定义的视图
执行聚合的视图(例如 GROUP BY、SELECT DISTINCT 或其他复杂转换)会失去与底层表结构的直接关系。因此,对基表进行的架构优化可能无法为对视图执行的图查询带来相同的性能优势。当视图执行复杂的聚合时,请仔细评估您的使用情形的查询性能。
使用基于视图的图表修改数据
视图不是具体化的,这意味着它们不会将定义视图的查询结果作为表存储在数据存储空间中,并且是只读的。因此,如需在通过视图创建的图表中插入、更新或删除节点或边,您需要修改用于创建视图的表中的数据。
图表错误处理,以确保数据完整性
使用视图定义图元素时,请对底层基本表强制执行数据完整性(例如,强制执行数据类型)。否则,基表中的数据可能无效,并导致基于视图的图表的查询在运行时失败。
例如,当您从无架构过渡到正式的图时,请使用 CHECK 限制条件来验证基本表(GraphNode 和 GraphEdge)中的数据。以下代码在 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));
后续步骤
了解如何从 SQL 视图创建属性图表。
了解 Spanner Graph 架构。