本文概述
- 转向Google BigQuery
- 样本数据
- 检测结果
- BigQuery的性能和结论
- 使用BigQuery有意义时
如果报告基于少量数据, 则可以通过在关系数据库下编写SQL查询来解决该任务。在此步骤中, 重要的是要了解编写查询的基础知识以及如何使查询更快和更有效。但是, 有时报告依赖于更大的数据集(例如, 表中有数百万和更多的行), 但是报告并不依赖于输入变量(参数), 或者你可能会发现值的数量非常少。在这种情况下, SQL查询可能会很慢, 因此对于用户来说, 等待执行查询并不是最佳选择。在这种情况下, 最常见的做法是在客户端请求报告之前提前运行查询。
而且, 它需要实现一些缓存功能, 因此客户端可以从缓存中获取数据, 而不是实时运行查询。如果你不需要显示实时数据, 则此方法非常有效。它可以显示一个小时甚至一天之前计算出的数据。因此, 实际报告/图表是使用缓存的数据显示的, 而不是基于实时数据的。
转向Google BigQuery 在从事制药行业的分析项目时, 我需要将邮政编码和药品名称作为输入参数的图表。我还需要展示美国特定地区的毒品之间的一些比较。
分析查询非常复杂, 最终在我们的Postgres服务器(带16 GB RAM的四核CPU)上运行了大约50分钟。我无法提前运行它并缓存结果, 因为查询将邮政编码和药品作为输入参数, 因此存在成千上万种组合, 并且无法预测哪个客户会选择。
即使我想尝试执行所有输入参数组合, 我的数据库也很可能崩溃了。因此, 是时候选择其他方法并选择一些易于使用的解决方案了。该图表对客户端很重要, 但是, 客户端尚未准备好对体系结构进行重大更改或完全迁移到另一个DB。
在该特定项目中, 我们尝试了几种不同的方法:
- 服务器的垂直缩放(将RAM和CPU添加到Postgres服务器)
- 使用替代数据库, 例如Amazon Redshift和其他数据库。
- 我们还研究了NoSQL解决方案, 但是大多数解决方案都很复杂, 需要对体系结构进行很多更改, 其中许多更改对于客户端而言可能太大了。
BigQuery是基于REST的Web服务, 它使你可以在大量数据下运行基于SQL的复杂分析型查询。将数据上传到BigQuery并执行与Postgres相同的查询(语法极为相似)后, 我们的查询运行得快得多, 大约需要一分钟才能完成。最终, 我们通过使用其他服务而获得了50倍的性能提升。值得一提的是, 其他DB并没有提供相同的性能提升, 我们要大方一些, 只是说它们还差得远。老实说, BigQuery所带来的性能提升给我留下了深刻的印象, 因为这些数据比我们任何人都希望的要好。
【什么时候使用Google BigQuery有意义()】尽管如此, 我还是不会将BigQuery宣传为世界上最好的数据库解决方案。尽管它对我们的项目效果很好, 但它仍然有很多限制, 例如每天表中更新的数量有限, 每个请求的数据大小受到限制等。你需要了解, BigQuery不能用来替代关系数据库, 它是针对运行分析查询的, 而不是针对简单的CRUD操作和查询的。
在本文中, 我将尝试比较Postgres(我最喜欢的关系数据库)和BigQuery在现实中的用例场景。另外, 我会在此过程中提供一些建议, 即我对使用BigQuery何时有意义的意见。
样本数据 为了比较Postgres和Google BigQuery, 我按照国家, 年龄, 年龄和性别对每个国家/地区进行了公开的人口统计信息(你可以从此链接下载相同的数据)。
我将数据添加到四个表中:
- 人口
- 地点
- 年龄组
- 人口总数
文章图片
我最终得出的人口表包含超过690万行。虽然不算太多, 但足以进行我的测试。
根据示例数据, 我尝试构建可用于构建现实生活中的分析报告和图表的查询。因此, 我为下一份报告准备了查询:
- 美国的人口按年累加。
- 从最大的国家开始, 所有国家的2019年人口。
- 每年排名前五的” 最古老” 国家。 “ 最古老的” 是指60岁以上人口占总人数百分比最高的国家。该查询每年应给出五个结果。
- 按年度汇总的前五名国家中, 男性和女性人口之间的差异最大。
- 从” 最老” 到” 最年轻” 的国家/地区, 获取每年每个国家/地区的中位数(平均)年龄。
- 每年找出排名前五的” 垂死” 国家。 “ 就寝” 是指人口在减少的国家(人口最多的国家)。
我总共建立了24个查询:
- 对于使用非汇总表(填充, 位置, age_groups)的Postgres DB为6
- 对于Postgres DB, 使用人口统计表6
- 使用汇总表和非汇总表的BigQuery的6 + 6查询。
美国按年份汇总的人口查询:
select
sum (value), year
from
world_population.populations_aggregated
where
location_name = 'United States of America'
group by
2
order by
year asc
查询每个国家/地区每年的年龄中位数, 从最旧到最年轻排序:
--converts age to number
with population_by_age_year_and_location as(
select
sum (value) as value, cast (regexp_replace(age_group_name, '\\+', '') as int64) as age, year, location_name
from
world_population.populations_aggregated
where
location_type = 'COUNTRY'
group by 2, 3, 4), --calculates total population per country per year
total_population_by_year_and_locations as (
select
sum(value) as value, year, location_name
from
population_by_age_year_and_location
group by
2, 3
), --calculates total number of people in country per year
age_multiplied_by_population_temp as (
select
sum(value * age) as value, year, location_name
from
population_by_age_year_and_location
group by
2, 3
), median_per_year_country as (
select
a.value / b.value as median, a.year, a.location_name
from
age_multiplied_by_population_temp a
inner join total_population_by_year_and_locations b on a.location_name = b.location_name and a.year = b.year
)select * from median_per_year_country
order by year desc, median desc
注意:你可以在我的bitbucket存储库中找到所有查询(链接在本文结尾)。
检测结果 为了运行查询, 我使用了两个不同的Postgres服务器。第一个具有1个CPU内核和4GB RAM, 并由SSD驱动器支持。第二台服务器具有16个CPU内核, 64GB RAM, 并且还使用SSD驱动器(第二台服务器具有16倍的CPU和RAM潜力)。
另外, 请注意, 在运行测试期间, 数据库上没有负载。我创建它们仅用于运行查询。在现实情况下, 查询会花费更长的时间, 因为其他查询可能同时运行, 此外, 并行运行的那些查询可以锁定表。为了检查查询速度, 我使用了pgAdmin3和BigQuery Web界面。
在测试中, 我得到了以下结果:
Postgres (1 CPU 4 RAM, SSD) |
Postgres (16 CPU 64 RAM, SSD) |
大查询 | ||||
汇总 | 未汇总 | 汇总 | 未汇总 | 汇总 | 未汇总 | |
Query 1 (US Population aggregated by Years) | 1.3秒 | 0.96秒 | 0.87s | 0.81秒 | 2.8秒 | 2.4秒 |
Query 2 (Population by Countries in 2019) | 1.1秒 | 0.88秒 | 0.87s | 0.78秒 | 1.7秒 | 2.6秒 |
Query 3 (Top 5 Oldest nations by years) | 34.9秒 | 35.6秒 | 30.8秒 | 31.4秒 | 15.6秒 | 17.2秒 |
Query 4 (Top 5 Countries with the biggest difference in male and female population) | 16.2秒 | 15.6秒 | 14.8秒 | 14.5s | 4.3秒 | 4.6秒 |
Query 5 (Age median per country, year) | 45.6秒 | 45.1秒 | 38.8秒 | 40.8秒 | 15.4秒 | 18岁 |
查询6(每年排名前5位的” 垂死” 国家) | 3.3秒 | 4.0秒 | 3.0秒 | 3.3秒 | 4.6秒 | 6.5s |
文章图片
注意:Postgres数据库位于美国服务器上, 而我位于欧洲, 因此Postgres传输数据会有额外的延迟。
BigQuery的性能和结论 根据我得到的结果, 我得出以下结论:
- 如果纵向扩展Postgres, 即使是16倍, 它在运行单个查询时也只能提供10-25%的性能。换句话说, 只有一个CPU内核和4GB RAM的Postgres服务器运行查询的时间与具有16个CPU内核和64GB RAM的服务器所需的时间非常相似。当然, 较大的服务器可以处理更大的数据集, 但是, 这并没有在查询执行时间上带来很多改进。
- 对于使用小型表的Postgres联接(位置表具有约400行, age_groups具有100行), 与在位于一个表中的聚合数据下运行查询相比, 它们不会产生巨大差异。此外, 我发现对于运行一到两秒钟的查询, 使用内部联接的查询速度更快, 但是对于长时间运行的查询, 情况则有所不同。
- 在BigQuery中, 具有联接的情况完全不同。 BigQuery不喜欢加入。使用聚合数据和非聚合数据的查询之间的时间差异很大(对于查询3和$ 5, 查询时间大约是两秒钟)。这意味着, 对于BigQuery, 你可以根据需要执行任意多个子查询, 但是为了获得良好的性能, 查询应使用一个表。
- 对于使用简单聚合或过滤或使用小型数据集的查询, Postgres速度更快。我发现在Postgres中花费不到五秒钟的查询在BigQuery中的运行速度较慢。
- 对于长时间运行的查询, BigQuery的性能要好得多。随着数据集大小差异的增加, 完成这些查询所花费的时间也会随之增加。
- 当查询在关系数据库中运行超过五秒钟时, 请使用它。 BigQuery的想法是运行复杂的分析查询, 这意味着运行简单聚合或过滤的查询毫无意义。 BigQuery适用于使用大量数据进行操作的” 大量” 查询。数据集越大, 使用BigQuery获得的性能就越高。我使用的数据集只有330 MB(兆字节, 甚至不是千兆字节)。
- BigQuery不喜欢联接, 因此你应该将数据合并到一个表中以缩短执行时间。 BigQuery允许将查询结果保存在新表中, 因此要创建新的汇总表, 只需将所有数据上传到BigQuery, 运行将合并所有数据的查询, 然后将其保存在新表中即可。
- BigQuery适用于数据不经常更改且你要使用缓存的情况, 因为它具有内置缓存。这是什么意思?如果你运行相同的查询, 并且表中的数据未更改(更新), 则BigQuery将仅使用缓存的结果, 而不会尝试再次执行查询。而且, BigQuery不会为缓存的查询收费。注意:即使是缓存的查询, 也需要1-1.2秒才能返回结果。
- 当你想减少关系数据库的负载时, 也可以使用BigQuery。分析查询” 繁重” , 在关系数据库下过度使用它们会导致性能问题。因此, 你最终可能会被迫考虑扩展服务器。但是, 使用BigQuery, 你可以将这些正在运行的查询移至第三方服务, 因此它们不会影响你的主要关系数据库。
链接
你可以在此处找到本文中使用的示例数据, 而在此处可以访问CSV格式的查询和数据。
推荐阅读
- 使你的应用获利,第2部分–利用移动渠道
- MCMC方法(Metropolis-Hastings和贝叶斯推理)
- 通过BERT加速(NLP优化模型)
- 从Oracle到SQL Server和从SQL Server到Oracle的迁移指南(1)
- Spring 梳理 - javaConfig在App和webApp中的应用
- Web Application Vulnerablities
- 互联网“寒冬”不想被辞退,Android程序员该如何应对()
- 安卓基础之缩放加载本地大图
- mapper代理查询