google-cloud-spanner - 当强制对非交错索引进行查询时,会有任何数据局部性好处吗?
问题描述
假设以下架构:
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
zap.extraData
现在,我们在这里丢失了 CASCADE DELETE,因此交错并创建附加索引并将其存储到索引中以使其不必返回 Zap 表来提取该信息可能仍然值得。
问题仍然是:仅在非交错索引上查询/加入时,数据局部性是否会发挥作用?
解决方案
正如我从文档中了解到的那样,如果索引没有交错并且您通过索引查询/加入,则数据位置无关紧要。如果您打算使用索引进行查询,则只需交错索引即可。
无论如何,正如您所解释的,如果您对该语句感兴趣,您可以继续在表上使用 interleaving ,因为如果没有 interleavingON DELETE CASCADE
就无法完成。
说明:
给定一个包含列的表,
primaryId
并且secondaryId
该表的主键在哪里primaryId
。在上创建二级索引secondaryId
会将其排除在交错到表中。
是的。
如果索引没有交错,则没有数据局部性在起作用
取决于查询。非交错索引和基表之间的连接不是本地的。您应该考虑STORING
索引中的子句以避免连接。表与其父级之间的连接将是本地的。
查询解释仪表板是一个有用的工具,可以显示 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 re:数据拆分。
是的。
如果索引可以交错,那将是一个好处,但这些交错索引中的键必须共享(就像任何交错表一样)。位置权衡的文档:“专注于为最重要的根实体和最常见的访问模式获取所需的位置,并在需要时让不太频繁或对性能不太敏感的分布式操作发生。”
是的。
推荐阅读
- c++ - 使用辅助函数创建树函数
- odoo - 如何使用继承类型委托创建完整记录?
- sql - 如何将选择语句表述为某个属性是否达到某个域值;选择不存在的值
- apache-kafka - 如何从另一个流处理器访问 KStreams 物化状态存储
- linux - 来自emacs的Ubuntu Linux python绘图,无法从'PIL'导入名称'_imaging'
- java - 关于使用 CompletableFuture 的建议
- jquery - 对动态添加的项目进行排序
- android - 在android studio中以编程方式减少android设备的蓝牙范围
- node.js - 是否可以将 SSL 证书添加到现有部署?
- ruby-on-rails - 使用代理的请求被 Web 服务器阻止但浏览器没有