已编辑使用公共数据集
我有一个包含以下架构的表,您可以在此处访问: https://bigquery.cloud.google.com/table/realself-main:rs_public.test_count
如果我运行以下查询,我会得到 cnt1 与 cnt2 的不同结果。
SELECT
COUNT(*) AS cnt1,
COUNT(dr_id) as cnt2,
FROM (SELECT * FROM rs_public.test_count) AS tc
WHERE
tc.is_published
如果我从where子句中删除 tc 别名,我会得到两个计数相同的结果:
SELECT
COUNT(*) AS cnt1,
COUNT(dr_id) as cnt2,
FROM (SELECT * FROM rs_public.test_count) AS tc
WHERE
is_published
但是,如果我重复第一个查询但使用where子句中的 is_claimed 字段,我会再次获得相同的计数。
SELECT
COUNT(*) AS cnt1,
COUNT(dr_id) as cnt2,
FROM (SELECT * FROM rs_public.test_count) AS tc
WHERE
tc.is_claimed
我认为这是一个错误并且BigQuery变得混乱,因为 is_published 是外部字段,也是 cover_photos 记录的叶字段。在评估结果是否应该展平时,错误地使用 cover_photos.is_published 字段 - 但在根据where子句过滤结果时使用外部 is_published 字段。
以下是没有使用select *的反例,我在下面对Felipe的回答的评论中提到了这一点:
SELECT
COUNT(*)
FROM (
SELECT
dr_id,
cover_photos.is_published
FROM
[realself-main:rs_public.test_count] )
返回3.
SELECT
COUNT(*), COUNT(0)
FROM (
SELECT
dr_id,
cover_photos.is_published
FROM
[realself-main:rs_public.test_count] )
返回7和3!根据我的评论,似乎唯一安全的选择是永远不要使用count(*)
答案 0 :(得分:1)
如果可以通过多种方式解释查询,BigQuery将尽最大努力猜测您的意图是什么 - 有时产生非一致的结果。这对每个数据库都是如此,因为SQL有这些含糊不清的空间。
解决方案:消除查询中的歧义 - 可能两种结果都是正确的,具体取决于您要计算的内容。
(通过不使用*来消除歧义,并使前缀显式化,同时您还可以明确请求表格平铺的方式)
我真的想评论您的具体数据和结果,但鉴于您没有提供公开样本,我不能。
答案 1 :(得分:1)
感谢分享@alan的数据集!让我们看看它的外观:
这是一个有趣的表:它有3列3行(很小,但是普通的SQL表)。有趣的是,第3列可以托管嵌套记录。在第一行它没有(null),第二行只有1个值,第三行有5个不同的嵌套值。
当您按列开始计算时,事情会变得很有趣:
SELECT COUNT(*)
FROM [realself-main:rs_public.test_count]
3
这是有道理的,数据集有3行。
SELECT COUNT(dr_id)
FROM [realself-main:rs_public.test_count]
3
这也是有道理的,有3个dr_id。
SELECT COUNT(cover_photos.is_published)
FROM [realself-main:rs_public.test_count]
6
现在事情变得更有趣了。它是6,因为cover_photos.is_published有6个值(null值不计算)。
SELECT COUNT(cover_photos.is_published), COUNT(dr_id)
FROM [realself-main:rs_public.test_count]
6 3
这仍然有意义:6 cover_photos.is_published,3 dr_id。
SELECT COUNT(*)
FROM (
SELECT cover_photos.is_published, dr_id
FROM [realself-main:rs_public.test_count]
)
3
这也很有趣:如果我们进行子查询,COUNT(*)会查看返回的行数。返回了3行。这仍然有意义。
但是:
SELECT COUNT(*), COUNT(cover_photos.is_published)
FROM (
SELECT cover_photos.is_published, dr_id
FROM [realself-main:rs_public.test_count]
)
7 6
7和6.七?为什么7?
嗯,BigQuery必须为子查询选择一个展平策略。看看我粘贴在那里的表 - 你能看到它有7行吗?这是计算的七行。
让我们明确地看一下它们:
SELECT dr_id, cover_photos.is_published
FROM (
SELECT cover_photos.is_published, dr_id
FROM [realself-main:rs_public.test_count]
)
请参阅?那是七排。选择具有嵌套记录的行(BigQuery的一个很好的功能)时,BigQuery有时需要展平数据以处理某些查询。前两行被扁平化为2行(一行有一个cover_photos.is_published为null),第三行被展平为5行,每行为cover_photos.is_published。
故事的寓意是在使用嵌套数据时要小心:有些查询会以对用户来说意外的方式将其弄平,但这在计算机尝试决定时会非常有意义。
根据要求,让我们更进一步:
看看这两个查询之间的区别:
SELECT COUNT(*)
FROM (
SELECT *
FROM (
SELECT * FROM [realself-main:rs_public.test_count]
WHERE is_published
)
)
SELECT COUNT(*)
FROM (
SELECT *
FROM (
SELECT * FROM [realself-main:rs_public.test_count]
)
)
WHERE is_published
在查看结果之前,您能猜出每个查询会给您带来什么结果吗?不,你不能。这两个查询都不明确,因此为了得到答案,BigQuery需要做出一些猜测和优化。
第一个查询的结果是7,第二个查询的结果是3.去试试。
有什么区别?好吧,通过查看这些查询的结果,我可以看出,在第二个中,BigQuery看到您感兴趣的唯一列是'is_published',因此它优化了树,因此只读取该列。但是BigQuery更难以优化第一个查询 - 所以它猜测“也许他们真的想要*,而*意味着我需要在将表传递到下一层之前将其展平”。它使表变平,所以后来最上面的查询看到7行。
这些结果是否有保证?不 - 查询含糊不清。如何减少歧义?不要使用“SELECT *”,而是告诉BigQuery你要查找哪些列 - 所以它不需要为你猜测。
答案 2 :(得分:1)
我正在添加一个新的答案,因为你不断添加问题的元素 - 他们都应该得到不同的答案。
你说这个问题令你感到惊讶:
SELECT COUNT(*), COUNT(0)
FROM (
SELECT dr_id, cover_photos.is_published
FROM [realself-main:rs_public.test_count] )
你很惊讶,因为结果是7和3。
如果我尝试这个可能会有意义:
SELECT COUNT(*), COUNT(0),
GROUP_CONCAT(STRING(cover_photos.is_published)),
GROUP_CONCAT(STRING(dr_id)),
GROUP_CONCAT(IFNULL(STRING(cover_photos.is_published),'null')),
GROUP_CONCAT("0")
FROM (
SELECT dr_id, cover_photos.is_published
FROM [realself-main:rs_public.test_count]
)
请参阅?它是相同的查询,加上4个相同子列的不同聚合,其中一个由嵌套的重复数据组成,并且在一行中也有一个空值。
查询结果如下:
7 3 1,1,1,0,0,0 1234,4321,9999 null,1,1,1,0,0,0 0,0,0
7来自嵌套数据的完全扩展为7行,如第5列提示。 3来自于仅评估“0”三次,如第6列所示。
这些细微之处都与使用嵌套重复数据有关。我建议你不要使用嵌套的重复数据,直到你准备好接受在处理嵌套的重复数据时会发生这些细微之处。