90%的Spark开发者没搞懂:SerDe和DataSource到底怎么选?选错性能差一半!
1.建表方式不同对于SerDe我们使用stored as建表是默认的对于Parquet和Orc格式不但要使用stored as还要把spark.sql.hive.convertMetastoreParquet/Orc开关置为false。// 先把自动转化为Spark 内部的Parquet的优化给关了 set spark.sql.hive.convertMetastoreParquetfalse; CREATE TABLE whujian8888.tianyancha_company_annual_report_lcx_hive2 ( report_year STRING COMMENT 年报年份, publish_time STRING COMMENT 发布时间, social_credit_code STRING COMMENT 统一社会信用代码/注册号, company_name STRING COMMENT 企业名称, company_telephone STRING COMMENT 企业联系电话, company_status STRING COMMENT 企业经营状态, company_email STRING COMMENT 电子邮箱, company_contact_address STRING COMMENT 企业通信地址, employee_num STRING COMMENT 从业人数, insurance_basic_older STRING COMMENT 城镇职工基本养老保险, insurance_birth STRING COMMENT 生育保险, insurance_injury STRING COMMENT 工伤保险, insurance_basic_employee STRING COMMENT 职工基本医疗保险, insurance_lose STRING COMMENT 失业保险, snapshot_mouth STRING COMMENT 数据更新快照月份, task_id STRING COMMENT 分批任务标识, spider_name STRING COMMENT tianyancha_company_annual_report 特定字段kafka分流入库, insert_time STRING COMMENT 数据采集时间, uniq_key STRING COMMENT 数据唯一标识, day STRING COMMENT 入库日期 ) stored as parquet;对于DataSource我们使用USING需要显示指定CREATE TABLE whujian8888.tianyancha_company_annual_report_lcx_spark2 ( report_year STRING COMMENT 年报年份, publish_time STRING COMMENT 发布时间, social_credit_code STRING COMMENT 统一社会信用代码/注册号, company_name STRING COMMENT 企业名称, company_telephone STRING COMMENT 企业联系电话, company_status STRING COMMENT 企业经营状态, company_email STRING COMMENT 电子邮箱, company_contact_address STRING COMMENT 企业通信地址, employee_num STRING COMMENT 从业人数, insurance_basic_older STRING COMMENT 城镇职工基本养老保险, insurance_birth STRING COMMENT 生育保险, insurance_injury STRING COMMENT 工伤保险, insurance_basic_employee STRING COMMENT 职工基本医疗保险, insurance_lose STRING COMMENT 失业保险, snapshot_mouth STRING COMMENT 数据更新快照月份, task_id STRING COMMENT 分批任务标识, spider_name STRING COMMENT tianyancha_company_annual_report 特定字段kafka分流入库, insert_time STRING COMMENT 数据采集时间, uniq_key STRING COMMENT 数据唯一标识, day STRING COMMENT 入库日期 ) using parquet;对于存量表我们可以使用show create table的方式查看他们是SerDe表还是DataSource表。我们可以看到整体是一样的在表现都是用USING但是我们会发现SerDe表多了一个TBLPROPERTIES尤其是有个属性transient_lastDdlTime即建DDL的时间在DataSource中是没有的。但是这个也不是绝对的主要还是因为对于parquet/orc表。2.Spark Web UI上的表现不同2.1 针对写表操作2.1.1 Hive SerDe写INSERT overwrite table whujian8888.tianyancha_company_annual_report_lcx_hive2 SELECT * from ods_exchange.tianyancha_company_annual_report_lcx;2.1.2 Spark DataSource写INSERT overwrite table whujian8888.tianyancha_company_annual_report_lcx_spark2 SELECT * from ods_exchange.tianyancha_company_annual_report_lcx;重点结论面试必备从上面我们可以看出往表里写数据的时候两者使用的类是不一样的对于SerDe使用的是InsertIntoHiveTable。而对于DataSource使用的是InsertIntoHadoopFsRelationCommand。2.2 针对读表操作2.2.1 Hive SerDe读SELECT COUNT(*) from whujian8888.tianyancha_company_annual_report_lcx_hive2;2.2.2 Spark DataSource读SELECT COUNT(*) from whujian8888.tianyancha_company_annual_report_lcx_spark2;重点结论面试必备从上面我们可以看出往表里写数据的时候两者使用的类是不一样的当看到“Scan hive”基本读取的都是Hive SerDe对应的源码读类是HiveTableScanExec除此之外我们能够看到的“Scan xxx”基本读取的都是Spark DataSource从上面我们可以看到对应的源码类是FileScan。而通过它的子类继承关系我们就明白了一切。但是该类只是一个特质并不是一个xxxExec那么真实对应的应该是FileSourceScanExec。同时我们也可以看到Hive SerDe读表在Spark Web UI上显示的指标只有一条而Spark DataSource显示的指标是非常丰富的。还有就是读取相同数据量的Hive SerDe表和Spark DataSource表启动的任务数也是不一样。最后就是两个使用的读取类是不一样的那么他们关于读取小文件的合并和大文件的切分的逻辑判别也是不一样的这里暂且不讨论后面会有详细的源码分析。3.写入文件名不同Data Source 模式写入文件时文件名带“.压缩类型.文件类型”后缀如Hive SerDe 模式写入文件时不带上述后缀如4.向量化读取不同Data Source 模式默认使用向量化读取性能高Spark 3.3 起嵌套字段ARRAY、STRUCT、MAP也支持向量化读取。由于 Hive 2.3 Parquet/ORC 向量化读取 bug 较多Hive SerDe 模式默认关闭此特性性能低。5.读取混合分区表的方式不同如表 t 为 Parquet 格式但其分区 hour01 为 Parquet 格式hour02 为 JSON 格式。Data Source 模式只识别表格式所有分区数据都按照表格式读取因此会报错Hive SerDe 模式可以识别每个分区的格式支持读取混合分区表因此可以正确读取数据。6.INSERT OVERWRITE 动态分区写入不同Data Source 模式写入时仅会调用 HMS API 删除或新增分区而不会更新已存在的分区元数据这种行为可能导致一些 OLAP 系统如 Impala无法感知分区数据变化。Hive SerDe 模式写入时会调用 HMS API 更新作业产出结果中涉及的所有分区的元数据。