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

问题描述

假设以下架构:

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

zap.extraData现在,我们在这里丢失了 CASCADE DELETE,因此交错并创建附加索引并将其存储到索引中以使其不必返回 Zap 表来提取该信息可能仍然值得。

问题仍然是:仅在非交错索引上查询/加入时,数据局部性是否会发挥作用?

标签: google-cloud-spanner

解决方案


正如我从文档中了解到的那样,如果索引没有交错并且您通过索引查询/加入,则数据位置无关紧要。如果您打算使用索引进行查询,则只需交错索引即可。

无论如何,正如您所解释的,如果您对该语句感兴趣,您可以继续在表上使用 interleaving ,因为如果没有 interleavingON DELETE CASCADE就无法完成。

说明:

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

是的。

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

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

查询解释仪表板是一个有用的工具,可以显示 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
    

    第二次查询

  • 它使用表Zap2(的非交错版本)而不是需要在第二个查询之间和中Zap的分布式连接。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 re:数据拆分。

是的。

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

是的。


推荐阅读