我继承了一个应用程序,它必须从各种类型的文件中读取数据,并使用OCI接口将数据移动到Oracle数据库中。大多数表都有大约40-50列,因此SQL插入语句变得非常冗长。
当我继承这段代码时,它基本上通过一系列strcat
作为C字符串构建了insert语句,然后将其传递给相应的OCI函数来设置和执行语句。但是,由于大部分数据都是直接从文件中读取到列值中,因此应用程序可以轻松地注入SQL。所以我试图使用绑定变量来解决这个问题。
在我可以找到的每个示例OCI应用程序中,每个变量都是静态分配和单独绑定的。这将导致相当多的样板,但是我想将它减少为某种循环结构。所以我的解决方案是,为每个表创建一个包含表列名称的字符串的静态数组:
const char const *TABLE_NAME[N_COLS] = {
"COL_1",
"COL_2",
"COL_3",
...
"COL_N"
};
以及一个使占位符不在列名中的简短函数:
void makePlaceholder(char *buf, const char *col);
// "COLUMN_NAME" -> ":column_name"
然后我循环遍历每个数组并将我的值绑定到每个列,生成占位符。这里的一个潜在问题是,因为每个列的类型各不相同,所以我将所有内容绑定为SQLT_STR
(字符串),因此期望Oracle在插入时转换为正确的数据类型。
所以,我的问题是:
对于具有大量列/参数的SQL插入语句,使用绑定变量的正确/惯用(如果SQL / OCI存在这样的事情)是什么?更一般地说,使用OCI制作这种类型的大型插入语句的最佳方法是什么?
与构建和使用vanilla C字符串相比,大量绑定调用的效率是否显着?
将所有变量绑定为字符串并允许Oracle进行正确的类型转换是否存在风险?
提前致谢!
答案 0 :(得分:1)
不确定这方面的C方面。我的答案将来自DBA的观点。
问题2: 始终使用绑定变量。它可以防止SQL注入并提高性能。
程序员经常忽视性能方面。当Oracle收到一个SQL时,它会生成整个SQL文本的哈希值,并查看其执行计划的内部存储库,看它是否有一个。如果使用绑定变量,那么每次运行查询时SQL文本都是相同的,而不管变量的值是什么。但是,如果您连接了字符串,那么您的自我Oracle将对SQL文本进行散列,包括(您应该放入的内容)变量的内容,每次都获取一个唯一的哈希值。因此,如果您使用绑定变量生成一个执行计划,那么Oracle会执行一百万次查询,而如果您不使用绑定变量,那么它将生成一百万个执行计划并浪费大量资源来执行此操作。