Chinaunix首页 | 论坛 | 博客
  • 博客访问: 46873
  • 博文数量: 13
  • 博客积分: 1497
  • 博客等级: 上尉
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-04 00:03
文章分类
文章存档

2011年(1)

2010年(1)

2009年(11)

我的朋友

分类: Mysql/postgreSQL

2009-04-12 00:30:32

根据自己有限的java数据库编程的经验,对sql做预处理可以提高执行的效率,所以对mysql的c API做了些探索。从好坏两方面来总结mysql提供的这些接口:
  好处是,他提供的是一种buffer的机制,我对它做了优化,就是为所有的参数buffer数据创建了一个大的静态的或者全局缓冲区,这样每次改变buffer内容的时候只需要对相应的字段赋值即可,不需要每次重新设置buffer指向的内存,因为这块内存是不变的,参数字段名字和这个内存地址做一个map,赋值的时候可以直接查找到参数的地址。如果有多个prepare statement,且是一个线程内,这块数据缓存可以共同利用,互不干扰的。如果用的hash_map,效率很高,每次参数赋值的消耗是很少的,几乎等同于变量赋值的。
  需要注意的是sql字段类型,buffer_type枚举,c ++数据类型之间的映射关系,必须保证不会内存越界。buffer_length可以不指定的,那样就会直接使用length了,当然这是update/insert,如果是select还是要有的。读了mysql的driver的源码才确定了在bind param的时候是如何赋值内存的,如果不是blob 或者buffer长度。在调试时,如果发现写到数据库的和程序中的值不一致,这是可能的问题根源。
  我不确定prepare statement在执行时究竟是走的拼sql的流程还是有一个专门的二进制协议来只传递参数值,源代码中这段没找到。我测出来的是执行prepare statement和直接执行sql语句的效率基本上是一致的,有很小很小的提高。
  因此,我确定,使用prepare statement的最大节省的是拼sql语句的消耗,如果拼的话往往要使用字符串流的机制,效率比较低,这部分的时间消耗等于执行sql的消耗。理想的情况,不适用prepare statement,弄一个sql语句,拼的时候在参数的地方预留缓冲区,然后赋值的时候就直接把值放到缓冲里,然后把sql直接执行就好了,难题在于变长的char*和blob的缓冲区如何分配,分配的一个足够大的缓冲,如果实际值不够长的话就填充空格。这个还在瞎想阶段,实现起来很难。
  使用了prepare statement也省去了escape特殊字符的麻烦,提高了安全性。
  问题在于我对一个prepare statement的各个参数每次用到的可能不同,这次用这个参数,不用另一个参数,这样prepare statement就不同了,只好重新建一个。如果有十几个字段,每次不确定用哪几个字段,这在只修改需要修改的内容时是必须的,为了减少不必要的存档生成,当然这个情景很特殊。。。却是我所面对的。如果能在param的buffer增加一个字段来表示这个字段是否有效就好了,可惜没有。
  prepare statement需要长期占用数据库连接,这个对于有限的连接数也是一个问题,又、需要有一个类似于连接池的prepare statement池机制啊。。。
  这就是我的总结了,具体代码网上搜一大堆。读了源代码收获比较大,它能让我完全确认它是如何工作的。  
   Great open source!
阅读(5900) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~