我在BigQuery中有一个输入表,其中所有字段都存储为字符串。例如,该表如下所示:
name dob age info
"tom" "11/27/2000" "45" "['one', 'two']"
在查询中,我目前正在执行以下操作
WITH
table AS (
SELECT
"tom" AS name,
"11/27/2000" AS dob,
"45" AS age,
"['one', 'two']" AS info )
SELECT
EXTRACT( year from PARSE_DATE('%m/%d/%Y', dob)) birth_year,
ANY_value(PARSE_DATE('%m/%d/%Y', dob)) bod,
ANY_VALUE(name) example_name,
ANY_VALUE(SAFE_CAST(age AS INT64)) AS age
FROM
table
GROUP BY
EXTRACT( year from PARSE_DATE('%m/%d/%Y', dob))
另外,我尝试执行一个非常基本的group by
操作,将项目强制转换为字符串而不是强制转换,并且在大约1M行的数据集上,我没有发现任何性能下降(实际上,在这种情况下) ,转换为字符串的速度更快):
除了“保留”所有字符串表而不将其转换为正确的类型是一种不好的做法外,通过保留所有表我会遇到哪些限制(无论是功能还是性能) -string而不是将其存储为适当的类型。我知道由于存储字符串而不是number / date / bool / etc等会导致大小略有增加,但是如果我保持这种方式会遇到什么主要的限制或性能影响呢?
在我的头顶上,我看到的唯一限制是:
但是这些似乎都是很小的东西,可以解决。还有其他“更大”的原因,为什么使用所有字符串字段会受到巨大的限制,无论是限制查询能力还是在各种情况下都对性能造成巨大影响?
答案 0 :(得分:3)
首先-我没有看到比您已经认识并征募过的更大的表演停止者
平均时间
尽管使用查询生成器并没有多大关系……
基于上面的摘录-我想谈谈这种方法的某些方面(将全部存储为字符串)
虽然我们通常关注从字符串到本机类型的CAST转换以应用相关功能,等等,但我意识到,在某些情况下,使用某种查询生成器构建复杂的通用查询需要相反的方法-将本机类型转换为字符串才能应用功能像STRING_AGG
[只是]作为一个简单示例
所以,我的想法是:
当表是为直接用户访问而设计的,它具有琐碎甚至复杂的查询时-具有本机类型是有益的,并且对性能而言是明智的,并且对用户而言更友好,易于理解等。
同时,如果您正在开发自己的查询构建器,并且设计了表,以便用户可以通过该查询构建器通过查询使用该表,并且已实现一些通用逻辑-将所有字段都设置为字符串在构建查询生成器本身时可能会有所帮助。
所以这是一个平衡-您可能会损失一些性能,但是可以更好地实现通用查询构建器,从而赢得胜利。而这种平衡取决于您的业务性质-既可以从数据预期的角度来看,也可以从您想支持的查询类型中得到
注意:您的问题范围很广,并且基于意见(顺便说一句,在SO方面没有得到太多尊重),因此,显然我的回答-完全是我的意见,但基于与BigQuery的丰富经验
答案 1 :(得分:0)
您可能会遇到一些性能和存储问题,可以在official documentation中找到一些指导。
我认为主要的性能问题将来自CAST操作,请记住,BigQuery Engine将不得不为每一行的每个值处理CAST操作。 为了显示Compute操作,让我们进行一个简单的查询:
SELECT
street_number
FROM
`bigquery-public-data.austin_311.311_service_requests`
LIMIT
5000
然后,我们检查执行细节中执行的阶段,并看到以下内容:
READ
$1:street_number
FROM bigquery-public-data.austin_311.311_service_requests
LIMIT
5000
WRITE
$1
TO __stage00_output
仅需要读,限制和写操作。但是,如果我们执行相同的查询并添加了强制转换操作。
SELECT
CAST(street_number AS int64)
FROM
`bigquery-public-data.austin_311.311_service_requests`
LIMIT
5000
我们看到还需要进行计算操作才能转换值:
READ
$1:street_number
FROM bigquery-public-data.austin_311.311_service_requests
LIMIT
5000
COMPUTE
$10 := CAST($1 AS INT64)
WRITE
$10
TO __stage00_output
很明显,如果您执行强制转换指令,则将需要执行Compute操作。这些计算操作可能会花费一些时间,在逐步增加操作大小时可能会导致问题。
另外,请记住,每次要使用每种数据类型的data type properties时,都必须转换值,并处理所需的Compute操作时间。
最后提到存储性能,正如您提到的那样,字符串没有固定的大小,这可能会导致大小增加。
答案 2 :(得分:0)
您是否可以将字符串"33/02/2000"
作为日期存储在一行中,将"21st of December 2012"
存储在另一行中,并且将"22ое октября 2013"
存储在另一行中?
您是否可以将字符串"45"
作为年龄存储在一行中,而"young"
则存储在另一行中?
年龄"10"
小于年龄"9"
时,您还可以吗?
数据类型在数据库级别提供了一些基本的数据验证机制。
BigQuery数据库是否具有索引概念?
如果是,那么一旦您开始将字符串转换为适当的类型(例如
),这些索引很可能就变得无用了SELECT
...
WHERE
age > 10 and age < 30
vs
SELECT
...
WHERE
ANY_VALUE(SAFE_CAST(age AS INT64)) > 10
and ANY_VALUE(SAFE_CAST(age AS INT64)) < 30
答案 3 :(得分:0)
通常,较少的列/行不会让您感到麻烦。当数据量巨大时,您会开始感到麻烦。
主要问题:
代码的维护:考虑将来可能会收到的要求。每次进行数据处理的转换都会增加代码的复杂性。例如,如果您的客户要求将来找回青少年,则需要将字符串转换为日期以获取年龄,然后才能进行操作。
数据大小:数据大小具有更广泛的影响,一开始是看不到的。例如,如果您有N个需要自己的测试系统的并行测试团队,则需要分配更多的磁盘空间。
读取性能:当您有更多字节要读取巨大的表时,这将花费您大量时间。例如,通常电信运营商每月有数十亿行数据。
如果代码复杂度增加,则需要在多个位置复制转换。
即使是上述项目中的任何一项,也应尽量避免将字符串用于所有内容。
答案 4 :(得分:0)
我认为与此有关的最大问题是,如果该表/数据还有其他用户,例如,如果有人试图用它来写报告并进行计算,图表或日期范围设置,那么始终使用他们使用的任何工具来投射或转换数据。您或某人可能会对此抱怨很多。
如果有人决定在此数据和转换所有数据的报告工具之间建立一层,那么您最好一次对表/数据进行一次处理即可。