【问题标题】:Spanner SQL Filtering by Less Than on Tuples按小于元组的 Spanner SQL 过滤
【发布时间】:2020-11-03 02:30:20
【问题描述】:

有没有办法在 Spanner SQL 查询的 WHERE 子句中实现 <, >, etc 比较,其中比较的值不是标量而是元组/结构?

例如,假设我们有一个表 users(故意不切实际的架构)

CREATE TABLE users (
    is_special BOOL NOT NULL,
    registered_on TIMESTAMP NOT NULL,
) PRIMARY KEY (is_special DESC, registered_on DESC)

PK 索引的自然排序顺序为is_special DESC, registered_on DESC

我想选择从该 PK 索引中的特定行开始的一系列行(即来自游标):

SELECT * FROM users 
WHERE (is_special, registered_on) < (@cursor.is_special, @cursor.registered_on)
LIMIT 100

Spanner SQL 不允许这样做,因为元组被视为 STRUCT 类型,而 STRUCT 类型不允许 &lt; 比较。有没有其他方法可以做到这一点?

使用 Read API,我可以通过使用 KeyRange 并提供我想要开始查询的行的 PK 来查询范围,但我想在 SQL 中实现同样的功能。

【问题讨论】:

  • 我没有找到关于此的具体示例,但官方文档herehere 可能会有所帮助。

标签: google-cloud-spanner


【解决方案1】:

以下是使用单个字段编写查询的方法。这依赖于 is_special 列不可为空这一事实。

SELECT * FROM users
WHERE (is_special < @cursor.is_special) OR (is_special = @cursor.is_special AND registered_on < @cursor.registered_on)
LIMIT 100

只是为了完整性;如果列 is_special 可以为空,那么它会变得更丑。

SELECT * FROM users
WHERE (is_special < @cursor.is_special) OR ((is_special = @cursor.is_special OR (is_special IS NULL AND @cursor.is_special IS NULL)) AND registered_on < @cursor.registered_on)
LIMIT 100

附加评论。该查询有一个LIMIT 子句,但没有ORDER BY 子句。这是合法但不寻常的,鉴于查询正在分页结果,这看起来像是一个错误。

我认为查询应该有以下子句:

ORDER BY is_special, registered_on

原因如下:

如果 SQL 查询没有 ORDER BY 子句,则它不提供任何行顺序保证。在实践中,即使没有 ORDER BY 子句,您也会在 Spanner 结果中观察到排序,但不能保证顺序,您不应依赖它。但是,如果查询具有 ORDER BY 并且 Spanner 使用提供所需顺序的索引,则 Spanner 不会显式对数据进行排序。因此,您无需担心包含 ORDER BY 的性能或内存影响。

【讨论】:

  • 啊,是的,意味着包括ORDER BY is_special, registered_on。尝试使用来自PRIMARY KEY (is_special DESC, registered_on DESC) 的索引时,使用OR 是否有问题,即它将无法使用索引的排序顺序?我已经以这种方式使用OR 对场景进行了测试,并最终进行了全表扫描。
  • 这是一个很好的观点。查询变得更加复杂,但它应该有助于在前导列上添加一个连词: SELECT * FROM users WHERE (is_special
  • 糟糕,我没有正确使用该查询文本的括号。这修复了括号:SELECT * FROM users WHERE (is_special &lt;= @cursor.is_special) AND ((is_special &lt; @cursor.is_special) OR (is_special = @cursor.is_special registered_on &lt; @cursor.registered_on)) ORDER BY is_special DESC, registered_on DESC LIMIT 100 。不幸的是,额外过滤器的好处将受到限制,因为前导列是BOOL 类型(扫描将从第一个FALSE 或第一个TRUE 开始)。
  • 我仔细看了看这个。您实际上不需要额外的谓词。 Spanner 足够聪明,可以使用索引在 OR 的每个元素上进行查找,以便在不执行完整扫描的情况下获取所有符合条件的行。
  • 感谢@Campbell-Fraser,让 Spanner 内部人士对此发表评论真的很有帮助。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 2016-09-04
相关资源
最近更新 更多