![大数据SQL优化:原理与实践](https://wfqqreader-1252317822.image.myqcloud.com/cover/4/53288004/b_53288004.jpg)
1.3 大数据SQL的弊端
SQL作为声明式语言降低了接入成本,大大增强了开发灵活性。但凡事有利弊,大数据引擎屏蔽了大量细节的描绘,大量优化和物理实现过程对用户不透明,当SQL执行性能有欠缺或者遇到瓶颈时,调优或者排查问题的过程和时间就会大幅增加。
1.3.1 易学难精
不同的SQL尽管描述的是相同的结果,但是在其底层实现、查询优化以及数据结构等因素的影响下,实际的执行开销可能会有很大差异,这非常考验开发人员的技术功底以及对各框架的了解程度。比如同样是统计每种交易类型的订单量和金额,消耗同样的资源,使用不同的写法,产生的时间开销就会不一样。
![](https://epubservercos.yuewen.com/E8B555/31751979803748806/epubprivate/OEBPS/Images/19_02.jpg?sign=1739621138-nd9WsK82PeB19byAMRvRRGsNODL96JCa-0-cf150750a009c91c2fb09965f94e374f)
![](https://epubservercos.yuewen.com/E8B555/31751979803748806/epubprivate/OEBPS/Images/20_01.jpg?sign=1739621138-cLuNyEFTDJFm5TMgLdcAKCXnDq92ijWr-0-7a349f155b5589062d7d9210ef03ce72)
语句1只是简单地对订单类型聚合后进行求和计数,而语句2运用了两阶段聚合的优化手段,虽然后者在写法上不便理解,但执行时长能减少50%左右。我们只有对执行的引擎有一定了解,才能在查询或执行遇到瓶颈时,得心应手地进行优化。
1.3.2 表达能力有限
SQL中缺乏一些必要的数据类型和运算定义,这使得某些高性能算法无法描述,只能寄希望于计算引擎在工程层面的优化。传统关系型数据库经过几十年的发展,优化经验已经相当丰富,但即便如此仍有许多场景难以被优化,理论层面的问题确实很难在工程层面解决。而大数据生态在优化方面的经验还远远不如传统数据库,算法上不占优势,就只能靠增加计算节点的数量来提高性能。
另外,SQL描述过程的能力不太好,不擅长指定执行路径,想获得高性能往往需要专门优化的执行路径,这又需要增加许多特殊的修饰符来人为干预,但这种做法不如直接使用过程性语言来得直接。此外,在复杂计算方面,SQL实现得很烦琐。例如统计所有直播间用户的观看时间,SQL的计算逻辑大致为,利用每5s发送一次的心跳事件来追踪用户的观看时长,这些心跳事件会应用在用户进入直播间、观看直播期间,并且没有将应用置于后台或退出时上报。查询任务如下所示。
![](https://epubservercos.yuewen.com/E8B555/31751979803748806/epubprivate/OEBPS/Images/20_02.jpg?sign=1739621138-mV5sskPwsOOYbXm1SZpyLOtpqYoTq55P-0-b5dbfad948c078066b0294e1d9c39244)
![](https://epubservercos.yuewen.com/E8B555/31751979803748806/epubprivate/OEBPS/Images/21_01.jpg?sign=1739621138-7eg9Dd0NxK8Th9IgWeWDzW6NyRmD19M5-0-8de99b4a9e9fa6359ee34962df56655b)
![](https://epubservercos.yuewen.com/E8B555/31751979803748806/epubprivate/OEBPS/Images/22_01.jpg?sign=1739621138-5wncdQMzhh0JpKXSkYEevI5OZplDGZub-0-7e8be9b741b14cdd24b75b98dc151f72)
为了满足上述要求这里采用了相当复杂的方法,以至于代码编写起来困难重重,仅是理解其中的逻辑,就要耗费大量时间。此外,利用SQL来执行过程性计算也非常困难。所谓过程性计算,就是那些不能一气呵成的计算过程,它们需要分多个步骤来完成,尤其是那些涉及数据顺序的复杂运算。例如统计一周内累计登录时长超过1h的用户占比,但要剔除登录时长小于10s的误操作情况;统计信用卡在最近3个月内最长连续消费的天数分布情况,考虑实施连续消费10天后积分3倍的促销活动;统计1个月中有多少用户在24h内连续进行了查看商品操作后加入购物车并购买的动作,有多少用户在中间步骤放弃购买。为了实现这类过程性运算,仅凭SQL去编写相应的逻辑往往难度较大,通常还需辅以UDF才能实现。如果连SQL代码都难以构建,那么SQL的使用效果将大打折扣。
1.3.3 与关系型数据库求同存异
大数据SQL在站在关系型数据库“巨人肩膀”上的同时,也存在着以下的差异或“弊端”。在大数据生态中,SQL语句不仅代表查询语句,也用来表达计算的过程。在关系型数据库中,MySQL的查询引擎和存储是紧耦合的,这其实是有助于优化性能的,不能把它们拆分开来。而大数据SQL的引擎一般都独立于数据存储系统之外,更为灵活一些。
在大数据生态中,SQL语句不仅可以表达静态数据集上的查询,还可以表示流计算的计算过程,也就是兼容离线数据分析和实时数据分析。流计算(流式SQL)是一种将传统的SQL查询语法与流式计算框架(如Apache Flink、Apache Kafka Streams、Apache Beam等)结合起来的方法,通过使用流式SQL,可以通过SQL的简洁和表达力来定义实时数据流的转换和处理逻辑。
大多数大数据引擎不支持索引和事务。大数据引擎面对的数据规模通常非常大,存储在分布式文件系统或分布式数据库中。传统的索引技术在大数据的情况下可能无法扩展,并且索引的维护和更新成本很高。大数据场景下的查询通常需要更加灵活和复杂,需要支持复杂的数据处理和分析操作。传统的索引技术可能无法满足这些需求,因为索引通常适用于简单的点查询或范围查询,而对于复杂的聚合、连接和多维分析等操作则效果有限。
在SQL开发或优化过程中,必须考虑具体的物理实现。在大数据生态中,大部分任务都基于“分而治之”的原则解决,也就是通过大内存、集群化和并行处理来实现。例如在SQL中,JOIN操作是基于键值对进行匹配的,但在大内存环境下,可以直接通过内存地址进行匹配,无须进行哈希计算和比对,这样可以显著提高性能。
SQL的数据表是无序的,单表计算可以较容易地实现分段切片并行处理。然而在进行多表关联运算时,通常需要预先设定固定的数据分段,难以实现动态数据分段。这同时也限制了SQL根据机器负载,动态决定并行处理数量的能力。在集群计算方面,SQL理论上不区分维度表和事实表,JOIN操作被简单地定义为笛卡儿积的生成与过滤。大规模表的JOIN操作不可避免地会引发占用大量网络资源的Shuffle操作。当集群节点过多时,网络传输引起的延迟可能会抵消增加节点带来的性能优势。