当强制对非交错索引进行查询时,会有任何数据局部性好处吗?
Posted
技术标签:
【中文标题】当强制对非交错索引进行查询时,会有任何数据局部性好处吗?【英文标题】:When forcing a query on a non-interleaved index(s), will there be any data locality benefit? 【发布时间】:2020-10-17 17:04:23 【问题描述】:假设以下架构:
CREATE TABLE Foo (
primaryId STRING(64) NOT NULL,
secondaryId STRING(64) NOT NULL,
extraData STRING(80),
active BOOL NOT NULL
) PRIMARY KEY (primaryId, secondaryId);
CREATE TABLE Bar (
primaryId STRING(64) NOT NULL,
secondaryId STRING(64) NOT NULL,
barId STRING(64) NOT NULL
) PRIMARY KEY (primaryId, secondaryId, barId),
INTERLEAVE IN PARENT Foo ON DELETE CASCADE;
CREATE TABLE Baz (
primaryId STRING(64) NOT NULL,
secondaryId STRING(64) NOT NULL,
barId STRING(64) NOT NULL,
bazId STRING(64) NOT NULL,
extraData STRING(80)
) PRIMARY KEY (primaryId, secondaryId, barId, bazId),
INTERLEAVE IN PARENT Bar ON DELETE CASCADE;
CREATE INDEX foo_primaryId_active ON foo (primaryId, active);
CREATE INDEX baz_bazId ON Baz (bazId);
我们有 3 个表 Foo、Bar、Baz,其中 Bar 在 Foo 中交错 和 Baz 在 Bar 中交错。以及 2 个非交错索引。
鉴于以下查询,我们将 FROM 和 JOIN 强制到索引上;没有明确的表格。
SELECT
baz.primaryId,
baz.secondaryId,
baz.bazId,
baz.extraData
FROM
Baz@FORCE_INDEX=baz_bazId AS baz
JOIN
Foo@FORCE_INDEX=foo_secondaryId_isActive AS foo
ON
foo.primaryId = baz.parimaryId AND foo.secondaryId = baz.secondaryId
WHERE
baz.bazId = @bazId -- using the baz_bazId index to query on the bazId
foo.active = true
在强制索引时,此查询是否具有数据局部性优势? 如果我们稍后添加第 4 个表 Zap 并在 Foo 上交错该表:
CREATE TABLE Zap (
primaryId STRING(64) NOT NULL,
secondaryId STRING(64) NOT NULL,
bazId STRING(64) NOT NULL,
extraData STRING(80)
) PRIMARY KEY (primaryId, secondaryId, bazId),
INTERLEAVE IN PARENT Foo ON DELETE CASCADE;
CREATE INDEX zap_bazId ON Zap (bazId);
并调整上述查询以包含第三个 JOIN:
JOIN
Zap@FORCE_INDEX=zap_bazId AS zap
ON
zap.bazId = @bazId AND zap.primaryId = foo.primaryId
WHERE
baz.bazId = @bazId -- using the baz_bazId index to query on the bazId
foo.active = true
zap.extraData IS NULL
我们会在这里获得任何数据本地化优势吗?因为我们正在查询所有非交错索引。我们的zap.extraData IS NULL
谓词未存储在索引本身中,因此可能需要运行回 Zap 表进行检查。
如果查询非交错索引没有数据局部性优势,我们是否可以放弃额外的zap_bazId
索引并仅更改 Zap 表,因为我们知道我们将专门查询它托管的数据的 bazId:
CREATE TABLE Zap (
bazId STRING(64) NOT NULL,
primaryId STRING(64) NOT NULL,
secondaryId STRING(64) NOT NULL,
extraData STRING(80)
) PRIMARY KEY (bazId, primaryId);
修改后的查询变为
JOIN
Zap AS zap -- using a table; aka the implicit PRIMARY_KEY index
ON
zap.bazId = @bazId AND zap.primaryId = foo.primaryId
WHERE
baz.bazId = @bazId AND -- using the baz_bazId index to query on the bazId
foo.active = true AND
zap.extraData IS NULL
现在,我们在这里丢失了 CASCADE DELETE,因此交错并创建附加索引并将zap.extraData
存储到索引中以使其不必返回 Zap 表来提取它可能仍然值得这些信息。
问题仍然是:仅在非交错索引上查询/加入时,数据局部性是否会发挥作用?
【问题讨论】:
【参考方案1】:据我从the documentation 了解到,如果索引没有交错并且您通过索引查询/加入,则数据位置无关紧要。如果您打算使用索引进行查询,则只需交错索引即可。
无论如何,正如您所解释的,如果您对 ON DELETE CASCADE
语句感兴趣,您可以继续在您的表上使用交错,因为它无法做到 without interleaving。
说明:
给定一个包含
primaryId
和secondaryId
列的表,其中表的主键是primaryId
。在secondaryId
上创建二级索引会将其排除在交错到表中。
是的。
如果索引没有交错,没有数据局部性在起作用
取决于查询。非交错索引和基表之间的连接不是本地的。您应该考虑索引中的STORING
子句以避免连接。表与其父级之间的连接将是本地的。
query explanation dashboard 是展示 Cloud Spanner 如何执行特定查询的有用工具。使用它我们可以分析上述查询。
baz_bazId
和 Baz
之间有一个分布式连接,foo_primaryId_active
有另一个分布式连接。
SELECT
baz.primaryId,
baz.secondaryId,
baz.bazId,
baz.extraData
FROM
Baz@FORCE_INDEX=baz_bazId AS baz
JOIN
Foo@FORCE_INDEX=foo_primaryId_active AS foo
ON
foo.primaryId = baz.primaryId AND foo.secondaryId = baz.secondaryId
WHERE
baz.bazId = @bazId -- using the baz_bazId index to query on the bazId
AND foo.active = true
在Zap
和zap_bazid
之间添加了一个分布式连接,它与其余的分布式连接。
SELECT
baz.primaryId,
baz.secondaryId,
baz.bazId,
baz.extraData
FROM
Baz@FORCE_INDEX=baz_bazId AS baz
JOIN
Foo@FORCE_INDEX=foo_primaryId_active AS foo
ON
foo.primaryId = baz.primaryId AND foo.secondaryId = baz.secondaryId
JOIN
Zap@FORCE_INDEX=zap_bazId AS zap
ON
zap.bazId = @bazId AND zap.primaryId = foo.primaryId
WHERE
baz.bazId = @bazId -- using the baz_bazId index to query on the bazId
AND foo.active = true
AND zap.extraData IS NULL
它使用表Zap2
(Zap
的非交错版本)而不是在第二个查询中需要Zap
和zap_bazid
之间的分布式连接。
SELECT
baz.primaryId,
baz.secondaryId,
baz.bazId,
baz.extraData
FROM
Baz@FORCE_INDEX=baz_bazId AS baz
JOIN
Foo@FORCE_INDEX=foo_primaryId_active AS foo
ON
foo.primaryId = baz.primaryId AND foo.secondaryId = baz.secondaryId
JOIN
Zap2 AS zap -- using a table; aka the implicit PRIMARY_KEY index
ON
zap.bazId = @bazId AND zap.primaryId = foo.primaryId
WHERE
baz.bazId = @bazId AND -- using the baz_bazId index to query on the bazId
foo.active = true AND
zap.extraData IS NULL
Spanner 将处理所有相关的网络 I/O 重新:数据拆分。
是的。
如果索引可以交错会有好处,但这些交错索引中的键必须共享(就像任何交错表一样)。位置权衡的文档:“专注于为最重要的根实体和最常见的访问模式获取所需的位置,并在需要时让不太频繁或对性能不太敏感的分布式操作发生。”
是的。
【讨论】:
只是为了确认,据我所知,要交错一个索引,它需要在与它被交错的表相同的主键组件上键入。因此,例如,给定一个包含列primaryId
和secondaryId
的表,其中表的主键是primaryId
。在 secondaryId
上创建二级索引会将其排除在交错到表中。
只是我自己澄清的另一个跟进。如果索引没有交错,没有数据局部性在起作用; Spanner 将处理所有相关的网络 I/O re:数据拆分。如果索引可以交错,会有好处,但这些交错索引中的键必须共享(就像任何交错表一样)。位置权衡的文档:“专注于为最重要的根实体和最常见的访问模式获取所需的位置,并在需要时让不太频繁或对性能不太敏感的分布式操作发生。”
@AdamVenturella 我已经更新了我的答案,请查看要求的说明。以上是关于当强制对非交错索引进行查询时,会有任何数据局部性好处吗?的主要内容,如果未能解决你的问题,请参考以下文章