JDBC内存管理—varchar2(4000)的影响

        今天在项目评审中遇到到一个问题,一个表的字段如comment,开发想用varchar2(4000),而我建议在满足应用场景的情况下,尽量减少长度,当时就抛出了一个问题,varchar2(4000)和varchar2(40)那个好,当时我也只是简单的回答了一下,说道varchar2(xx)的字段会在内存中分配空间大小为字段定义的长度。  回来后有想了想,自己也没有弄清楚其中的原来,于是问了问同事,查了查资料,说法都有理,如索引长度的限制 ,可以作为数据库层面的约束啊等等.最后还是翻了Oracle JDBC内存管理文档一读,终于明白了其中的原理。                        

        在10g中,oracle jdbc driver能够使用较大的内存,为了提高jdbc的性能,最重大的改变是在内存的使用上(内存换时间)。

        内存中主要用于存放查询结果,每个statement(如java中的prepared statement,callable statement)包括了两个buffers,一个为byte buffer,另一个为 char buffer。Char buffer用于存放所有字符类型的行,比如:char,varchar2,nchar等,byte buffer用于存储其他的数据类型的行。这些buffer在sql解析的时候分配,直到statement关闭(colse)的时候释放。

        Buffer的大小并不取决于查询返回的行的大小,当sql被解析后,driver根据每列的数据类型计算出最大的内存容量来存储每一列。

        同时,driver有一个fetchsize(指定每次使用Array Fetch 法检索出的数据行数。

    最佳数目取决于系统的性能:

   •如果数目太低,系统会多次检索少量数据,因而影响性能。

   •如果数目太高,系统执行检索操作的次数会降低,但每次需要更多的内存)

    那么在一次fetch时,driver就能根据每列长度和检索的行数计算出buffer的大小。

       Character data存储在char buffer之中,varchar2(10)的列将容纳最大长度的10字节,如果是定义为varchar2(4000)的列,则每行将占4000字节,不管实际中列存储了多少数据。在Driver知道查询结果之前,必须分配足够的内存用于存储可能最大的结果。

       Bfile,blob,raw和clob数据存储在byte buffer之中,这些数据类型能够达到4kbytes,需要每行至少4000bytes;其他的一些数据类型date,number每行大约为22bytes(估计值)。

         例子:CREATE TABLE TAB (ID NUMBER(10), NAME VARCHAR2(40), DOB DATE)

ResultSet r = stmt.executeQuery(“SELECT * FROM TAB”);

        当driver执行查询方法的的时候,数据库将解析sql,得到三列的信息:一列number(10),一列varchar2(40),一列date,第一列每行需要22字节,第二列每行需要40字节,第三列需要每行需要22字节,因此一行需要84字节,fetch size 为10行,那么dirver将会分配 char buffer:10*40=400 bytes;byte buffer将会分配:10*(22+22)=440bytes,总共840bytes。

           那么在定义varchar(4000)和定义varchar(20)的区别是很大的,varchar(4000)每行需要4000字节,而varchar(20)需要20字节,因此会造成内存空间的浪费。

         在明白了varchar字段在jdbc中分配内存的原理,设计表结构的时候,尽量避免使用varchar(large number),这样会给应用服务器节省一些内存,如果在大量连接访问的时候,RAM=connections*fetch的节省也是不可小视的。其实也可以想象一下,现实场景中,有那个用户会给你写到几千字的评论,又有谁查看你几千字的评论,那么在应用页面端就可以限制输入到db中的容量。

        可见在一些细小的问题上,也能制造出一些麻烦出来。注重细节,不可忽视。

上一篇:innodb中大字段的限制


下一篇:VMware的 Mount虚拟光驱问题