当强制对非交错索引进行查询时,会有任何数据局部性好处吗?

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 个表 FooBarBaz,其中 BarFoo 中交错BazBar 中交错。以及 2 个非交错索引。

鉴于以下查询,我们将 FROMJOIN 强制到索引上;没有明确的表格。

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。

说明:

给定一个包含primaryIdsecondaryId 列的表,其中表的主键是primaryId。在secondaryId 上创建二级索引会将其排除在交错到表中。

是的。

如果索引没有交错,没有数据局部性在起作用

取决于查询。非交错索引和基表之间的连接不是本地的。您应该考虑索引中的STORING 子句以避免连接。表与其父级之间的连接将是本地的。

query explanation dashboard 是展示 Cloud Spanner 如何执行特定查询的有用工具。使用它我们可以分析上述查询。

baz_bazIdBaz 之间有一个分布式连接,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

Zapzap_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

它使用表Zap2Zap 的非交错版本)而不是在第二个查询中需要Zapzap_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 重新:数据拆分。

是的。

如果索引可以交错会有好处,但这些交错索引中的键必须共享(就像任何交错表一样)。位置权衡的文档:“专注于为最重要的根实体和最常见的访问模式获取所需的位置,并在需要时让不太频繁或对性能不太敏感的分布式操作发生。”

是的。

【讨论】:

只是为了确认,据我所知,要交错一个索引,它需要在与它被交错的表相同的主键组件上键入。因此,例如,给定一个包含列primaryIdsecondaryId 的表,其中表的主键是primaryId。在 secondaryId 上创建二级索引会将其排除在交错到表中。 只是我自己澄清的另一个跟进。如果索引没有交错,没有数据局部性在起作用; Spanner 将处理所有相关的网络 I/O re:数据拆分。如果索引可以交错,会有好处,但这些交错索引中的键必须共享(就像任何交错表一样)。位置权衡的文档:“专注于为最重要的根实体和最常见的访问模式获取所需的位置,并在需要时让不太频繁或对性能不太敏感的分布式操作发生。” @AdamVenturella 我已经更新了我的答案,请查看要求的说明。

以上是关于当强制对非交错索引进行查询时,会有任何数据局部性好处吗?的主要内容,如果未能解决你的问题,请参考以下文章

当数据库强制加入时,如何强制执行更好的执行计划?

聚焦-聚集索引对非聚集索引的影响

oracle如何避免查询数据的时候索引失效

MySQL联合索引

oracle的SQL索引使用

高效合并交错索引数据