impala upsert into chang to insert into

文章讲述了用户在使用Impala客户端时遇到upsertinto语句被自动转换为insertinto的问题,分析了可能的原因(JDBC连接参数UseNativeQuery的影响),并介绍了如何通过调整参数来解决这个问题,以及提供了一些参考资料。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


记一次在impala 客户端中 upsert into 语法 被转换成 insert into

问题描述

用户反馈选择的impala数据源 执行的 upsert into 语句在实际执行时被转换成insert into 语句

数据

upsert INTO dw.test
SELECT  id         
       ,category   
       ,`type`      
       ,content    
       ,regexp_replace(detail,'\r\n|\r|\n','')  AS detail    
       ,status     
       ,gmt_create 
       ,gmt_modify 
       ,CURRENT_TIMESTAMP() AS load_time 
  FROM ods.test
-- Generation begins 
WHERE gmt_create < TO_DATE(NOW())
AND ums_update_time_ > UNIX_TIMESTAMP(DATE_SUB(TO_DATE(NOW()), 4)) * 1000; 

成变了

INSERT
	INTO
	`dw`.`test`
SELECT
	`ods`.`id`,
	`ods`.`category`,
	`ods`.`type`,
	`ods`.`content`,
	regexp_replace(`ods`.`detail`,
	'\\r\\n|\\r|\\n',
	'') as `detail`,
	`ods`.`status`,
	`ods`.`gmt_create`,
	`ods`.`gmt_modify`,
	NOW() as `load_time`
FROM
	`ods`.`test`
WHERE
	((`ods`.`gmt_create` < TO_DATE(NOW()))
		AND (`ods`.`ums_update_time_` > (UNIX_TIMESTAMP(DATE_SUB(TO_DATE(NOW()),
		4)) * 1000)))

结论

JDBC连接添加参数UseNativeQuery=1

启用此选项 (1) 时,驱动程序不会转换应用程序发出的查询,因此使用本机查询。禁用此选项 (0) 时,驱动程序会转换应用程序发出的查询,并将其转换为 Impala SQL 中的等效形式。

UseNativeQuery参数说明

分析过程

初步分析可能出现的问题点:

  1. 环境
  2. 程序中有拦截处理
  3. 参数
  4. 驱动

排查

简单排查

  • 问过运维同事都没有做过环境变更
  • 查看执行SQL任务的程序没有做过相应的变动
  • 询问负责加解密同事也不会对业务执行做拦截逻辑变更
  • 检查参考也未做变更

重现

  • 刨掉程序单独拿SQL在客户端执行

未重现

刚开始还是以为程序哪里做了拦截处理 调试源码
因为 om.cloudera.impala.jdbc驱动并未开源只能 边看程序边分析
源码分析时重现问题,并做出相应的调整

时序图分析

SQL HikariProxyCallableStatement ProxyPreparedStatement PreparedStatement Hive41PreparedStatement SPreparedStatement HiveJDBCStatement HiveJDBCDataEngine HiveJDBCNativeQueryExecutor HS2Client execute() execute() execute() extends extends createDataEngine() HiveJDBCDataEngine HiveJDBCDataEngine.prepare() 1.替换UPSERT语句为INSERT 2.声明此处为upsertQuery 3.决定是使用本地还是转换查询 4.调用本地createQuery ExecutorHiveJDBCDSIExtQueryExecutor prepare.replaceFirst("(?i)UPSERT", "INSERT") prepare.m_upsertQuery=true prepare.useNativeQuery=1 HiveJDBCNativeQueryExecutor execute() 核心执行类,在初始化的时候 决定是使用本地还是转换查询 如发现是UPSERT语句 则需要替换回去 executeHelper convertInsertToUpsert executeStatement(SqlStr) executeStatementInternal return result SQL HikariProxyCallableStatement ProxyPreparedStatement PreparedStatement Hive41PreparedStatement SPreparedStatement HiveJDBCStatement HiveJDBCDataEngine HiveJDBCNativeQueryExecutor HS2Client

源码调试分析

Hikar连接池执行SQL
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • impalajdbc41-2.5.30

            try {
                if (this.m_settings.m_platformVersionUtils.needsInsertOptimization(this.m_settings.m_serverVersion) && this.m_settings.m_optimizedInsert) {
                    boolean var3 = false;
                    boolean var15 = false;
                    IPTNode var16 = null;
                    if (var2.toUpperCase().startsWith("INSERT")) {
                        var3 = true;
                        DefaultLimitChecker var6 = new DefaultLimitChecker();
                        var6.initLimitCheckValues(this.getParentStatement().getParentConnection());
                        var16 = PTParser.parse(var1, var6);
                        if (null == var16) {
                            throw SQLEngineExceptionFactory.invalidParseTreeException();
                        }

                        LinkedList var7 = new LinkedList();
                        var7.add(var16);

                        label91:
                        while(true) {
                            while(true) {
                                if (var7.isEmpty()) {
                                    break label91;
                                }

                                IPTNode var8 = (IPTNode)var7.remove();
                                if (!var8.isTerminalNode()) {
                                    if (var8 instanceof PTNonterminalNode && ((PTNonterminalNode)var8).getNonterminalType() == PTNonterminalType.SELECT_STATEMENT) {
                                        var3 = false;
                                    }

                                    Iterator var9 = ((AbstractPTNonterminalNode)var8).getChildItr();

                                    while(var9.hasNext()) {
                                        IPTNode var10 = (IPTNode)var9.next();
                                        if (null == var10) {
                                            throw SQLEngineExceptionFactory.invalidParseTreeException();
                                        }

                                        var7.add(var10);
                                    }
                                } else if (var8 instanceof PTDynamicParameterNode) {
                                    var15 = true;
                                }
                            }
                        }
                    }

                    if (var3) {
                        try {
                            IQueryGenerator var17 = ((HiveJDBCCommonDriver)DSIDriverSingleton.getInstance()).getQueryGenerator();
                            var17.generate(var16, this.m_settings, (ExecutionContexts)null);
                            return new HiveJDBCNativeQueryExecutor(this.getLog(), this.m_hiveClient, this.m_statement, var2, var16, this.m_connection, this.m_isDirectExecuteQuery, this.m_requestMap, var15);
                        } catch (ErrorException var11) {
                            if (var11 instanceof SQLEngineException) {
                                var11.loadMessage(SQLEngineGenericContext.getDefaultMsgSource(), this.m_hiveClient.getWarningListener().getLocale());
                                LogUtilities.logWarning(var11, this.getLog());
                            }

                            return this.translateThroughEngine(var2);
                        }
                    } else {
                        return this.translateThroughEngine(var2);
                    }
                } else {
                    return this.translateThroughEngine(var2);
                }
            } catch (SQLEngineException var12) {
                var12.loadMessage(SQLEngineGenericContext.getDefaultMsgSource(), this.m_hiveClient.getWarningListener().getLocale());
                LogUtilities.logWarning(var12, this.getLog());
                int var4 = var12.getNativeErrorCode(SQLEngineGenericContext.getDefaultMsgSource(), this.m_hiveClient.getWarningListener().getLocale());
                if (12010 == var4 && !this.m_settings.m_platformVersionUtils.supportsNestedDataTypes(this.m_settings.m_serverVersion)) {
                    ErrorException var5 = HiveJDBCCommonDriver.s_HiveMessages.createGeneralException(HiveJDBCMessageKey.HIVE_QUERY_EXE_ERR.name(), new String[]{var12.getMessage(), "HY000", var2});
                    throw var5;
                } else {
                    this.m_hiveClient.getWarningListener().postWarning(new Warning(WarningCode.GENERAL_WARNING, 101, HiveJDBCMessageKey.DATABASE_TABLE_GENERAL_ERR.name(), new String[]{var12.getMessage()}));
                    return new HiveJDBCNativeQueryExecutor(this.getLog(), this.m_hiveClient, this.m_statement, var2, this.m_connection, this.m_isDirectExecuteQuery, this.m_requestMap);
                }
            } catch (ParsingException var13) {
                CoreUtils.postWarning(var13, this.m_hiveClient.getWarningListener(), WarningCode.GENERAL_WARNING, 101, HiveJDBCMessageKey.DATABASE_TABLE_GENERAL_ERR.name());
                return new HiveJDBCNativeQueryExecutor(this.getLog(), this.m_hiveClient, this.m_statement, var2, this.m_connection, this.m_isDirectExecuteQuery, this.m_requestMap);
            } catch (Exception var14) {
                CoreUtils.postWarning(var14, this.m_hiveClient.getWarningListener(), WarningCode.GENERAL_WARNING, 101, HiveJDBCMessageKey.HIVE_TRANSLATION_PREPARE_ERR.name());
                return new HiveJDBCNativeQueryExecutor(this.getLog(), this.m_hiveClient, this.m_statement, var2, this.m_connection, this.m_isDirectExecuteQuery, this.m_requestMap);
            }
        }
    }

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

调整参数后,也会减少一部分元数据处理的这种逻辑在这里插入图片描述

参考资料

相同问题参考
官方驱动配置参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值