2016-11-30 97 views
0

我正在使用JDBC PreparedStatement从Web服务查询Teradata数据库。我的表有一个PHONE_NUMBER列,存储为VARCHAR(10)。我一直用PreparedStatement setString()提供参数此列,如下图所示:Teradata JDBC无法将不带引号的VARCHAR识别为PreparedStatement参数

String myPhoneNumber = "5551234567";  
String sql = "SELECT * FROM MYTABLE " + 
      "WHERE PHONE_NUMBER = ? "; 
PreparedStatement p_stmt = db.getPreparedStatement(sql); 
p_stmt.setString(1, myPhoneNumber); 
ResultSet rs = db.executeQuery(p_stmt); 

它返回正确的结果,但我注意到Teradata的是使用该查询的CPU是相当高的。根据EXPLAIN计划,Teradata似乎将myPhoneNumber参数解释为FLOAT而不是VARCHAR,因此它必须执行数据转换才能将其与VARCHAR列PHONE_NUMBER进行比较。下面是说明计划的摘录:

... 
MYDATABASE.MYTABLE.PHONE_NUMBER (FLOAT, FORMAT 
'-9.99999999999999E-999'))= 5.55123456700000E 009) 

所以,我想出了下面的,这表明在CPU使用率(99.86%提高)有很大的改进:

String myPhoneNumber = "5551234567";  
String sql = "SELECT * FROM MYTABLE " + 
      "WHERE PHONE_NUMBER = ''||?||'' "; 
PreparedStatement p_stmt = db.getPreparedStatement(sql); 
p_stmt.setString(1, myPhoneNumber); 
ResultSet rs = db.executeQuery(p_stmt); 

所以我的问题是为什么这是必要的? setString不应该告诉JDBC告诉Teradata期望String/VARCHAR参数吗?

谢谢!

+1

这似乎很奇怪。 – Kayaman

+0

SetString不会在您的参数周围添加引号。从连接角度来考虑它。如果您对'select * from ... where phone_number ='和myPhoneNumber进行连接,则最终会出现'where phone_number = 5551234567'。它正在做你正在问的问题。 Teradata没有失败,而是默默地做了一个(非常昂贵的)隐式演员。 – Andrew

+2

@Andrew它不应该*有*。无论在线二进制格式是什么,都应该根据设置的参数类型来构造。引用是为了人类的可读性,数据库不需要它们。 – Kayaman

回答

0

你试过String myPhoneNumber = "'5551234567'";

注意 - 单引号列入包裹的价值。

如果您查看Teradata手册here中的示例,您会发现查询波段的设置方式与OP的第一个示例按照预期方式设置的方式相同,而没有单引号将其包装。在我看来,在OP的第一个例子中,这种行为是可以预料的。

编辑 Teradata为其JDBC驱动程序提供的示例代码是使用java.sql.PreparedStatment。通过这个例子,程序使用setString而没有任何技巧为INSERT语句提供字符串值。 Sample Code如果您无法复制该行为,我将使用Teradata GSC开启一个事件。

+1

这不是参数应该如何工作,它看起来与JDBC和SQL标准高度不兼容。 –

+0

你说得对。看起来Teradata的JDBC驱动程序不像预期的那样运行。 –

+0

根据评论和更多研究编辑回答 –