对数据表中大字段的处理方式
2017-08-17 13:25
190 查看
在数据库中,经常需要用到大字段类型,如oracle中long/blob/clob,sqlserver中text/image,mysql中的text/longtext/clob/blob。
存储的信息大概主要是两类,一类是长文本,如大段的文字,普通的varchar最长只能存储4000个汉字,已经不能满足要求;另一类是存储二进制信息,如上传的文件等。
那么假如现在有一个表,记录某人发布的文档信息,字段包括:发布人,发布时间,文档标题,文档内容(实际中还会有其它字段),一般建表如下(sqlserver):
create table document(
id int identity(1,1) not null,
createuser_id int,
document_title varchar(255),
document_context text);
这张表的结构,表面上看起来,从数据库设计角度和对应的JAVA类的设计来讲,都是没有问题的。
但实际上,这里面隐藏着两个比较严重的问题!
一、不能完全跨数据库
why?问题出在需要查重(distinct)的时候。
在需要查重时,采用纯jdbc技术,则可以自定义要查重的字段,如select distinct id,createuser_id,document_title from document。而当采用hibernate时,若不想自已创建若干个新的Pojo或者使用Object[]方式来处理数据,则只能使用select distinct d from document as d这样的语句,而hibernate会将其解析为类似:select distinct id,createuser_id,document_title,document_context from document。
问题就出在这个document_context字段上!
对于mysql来讲,hibernate生成的sql是可以执行的。但对于sqlserver来讲,是不允许在text/image列上进行distinct查询的!oracle中同样
4000
不可以对clob/blob进行distinct查询。
因此系统在sqlserver/oracle上部署时,当需要查重时则会出错。当然如果你用不到查重语句,是一点不受影响的。
二、严重影响列表显示和统计的效率
影响一张表的查询速度的,除了行数,还包括表所占的物理空间的大小。此表在数据量较小时,在查询方面感觉不到明显的差异。但是如果document_context字段所存储的数据都是大段文本或较大的文件时,会导致表的物理空间迅速变大,该字段所占用的空间有可能达到整表所占空间的90%以上。在此基础上,如果行数再增加到数十万、上百万级时,整个表所占的空间将达到一个惊人的数字。
保守估计,一条记录占用的空间平均为10K的话,一万条记录将占用100M的空间,一百万条记录将占用10G!在此表上的CRUD操作,亦将变慢,查询的速度亦会受到非常大的影响 。当然通过提高服务器本身的硬件性能和优化索引,可以提高查询速度,但面对无法预知的巨大洪水,单纯加固堤坝是不保险的。
解决的方式?
曾经处理过公司内的一个老系统,表的行数达到十万左右,由于采用上面的设计方式,虽然已经尽可能优化了索引,但查询分页时,仍然需要十秒左右。我单独建了一个新表,将document_context这个字段移到新表中,在原表中加一个对应的外键列,经过处理后,分页显示响应时间降到毫秒级以内。(二进制数据的转移是无法使用普通 的数据导入导出方式的,我的方法是复制该表,然后再修改复制后的表结构)
因为这个大字段,在最常用的列表显示中是根本不需要关心的,仅当用户需要查看某一记录的具体信息时,才需要调入该字段信息。因此分表后,显著提高了分页性能。
在我现在开发的所有的系统中,我都采用了上述的方式,这样做属于未雨绸缪,一旦系统部署后再修改,可能就来不及了。
补充:近日公司的另一套CMS系统,已经出现 了上述问题。clob字段直接置于业务表中,现业务表记录已达20余万,查询的速度非常缓慢,被迫采用各种方式来解决。如果当初设计时就考虑到这方面就不会有这样的问题了。
PS:解决方案之一是,可以在Pojo中加入构造函数,参数中包含除clob字段外的所有其它字段,通过select new Pojo(field1,field2,…..) from Pojo的方式来处理。但要注意,fieldx不能为集合类型,只能为基本数据类型或Po类型。如public Pojo(Long id,String name,User usr,Date createDate){}
以上转自:http://www.iteye.com/topic/27917
补充:我们其实现在还有更多的方案解决这个问题 ,例如,把文件文本等存在磁盘,数据库中保存相应的地址。调用的时候直接查询相应地址,根据地址去调用文件。
存储的信息大概主要是两类,一类是长文本,如大段的文字,普通的varchar最长只能存储4000个汉字,已经不能满足要求;另一类是存储二进制信息,如上传的文件等。
那么假如现在有一个表,记录某人发布的文档信息,字段包括:发布人,发布时间,文档标题,文档内容(实际中还会有其它字段),一般建表如下(sqlserver):
create table document(
id int identity(1,1) not null,
createuser_id int,
document_title varchar(255),
document_context text);
这张表的结构,表面上看起来,从数据库设计角度和对应的JAVA类的设计来讲,都是没有问题的。
但实际上,这里面隐藏着两个比较严重的问题!
一、不能完全跨数据库
why?问题出在需要查重(distinct)的时候。
在需要查重时,采用纯jdbc技术,则可以自定义要查重的字段,如select distinct id,createuser_id,document_title from document。而当采用hibernate时,若不想自已创建若干个新的Pojo或者使用Object[]方式来处理数据,则只能使用select distinct d from document as d这样的语句,而hibernate会将其解析为类似:select distinct id,createuser_id,document_title,document_context from document。
问题就出在这个document_context字段上!
对于mysql来讲,hibernate生成的sql是可以执行的。但对于sqlserver来讲,是不允许在text/image列上进行distinct查询的!oracle中同样
4000
不可以对clob/blob进行distinct查询。
因此系统在sqlserver/oracle上部署时,当需要查重时则会出错。当然如果你用不到查重语句,是一点不受影响的。
二、严重影响列表显示和统计的效率
影响一张表的查询速度的,除了行数,还包括表所占的物理空间的大小。此表在数据量较小时,在查询方面感觉不到明显的差异。但是如果document_context字段所存储的数据都是大段文本或较大的文件时,会导致表的物理空间迅速变大,该字段所占用的空间有可能达到整表所占空间的90%以上。在此基础上,如果行数再增加到数十万、上百万级时,整个表所占的空间将达到一个惊人的数字。
保守估计,一条记录占用的空间平均为10K的话,一万条记录将占用100M的空间,一百万条记录将占用10G!在此表上的CRUD操作,亦将变慢,查询的速度亦会受到非常大的影响 。当然通过提高服务器本身的硬件性能和优化索引,可以提高查询速度,但面对无法预知的巨大洪水,单纯加固堤坝是不保险的。
解决的方式?
曾经处理过公司内的一个老系统,表的行数达到十万左右,由于采用上面的设计方式,虽然已经尽可能优化了索引,但查询分页时,仍然需要十秒左右。我单独建了一个新表,将document_context这个字段移到新表中,在原表中加一个对应的外键列,经过处理后,分页显示响应时间降到毫秒级以内。(二进制数据的转移是无法使用普通 的数据导入导出方式的,我的方法是复制该表,然后再修改复制后的表结构)
因为这个大字段,在最常用的列表显示中是根本不需要关心的,仅当用户需要查看某一记录的具体信息时,才需要调入该字段信息。因此分表后,显著提高了分页性能。
在我现在开发的所有的系统中,我都采用了上述的方式,这样做属于未雨绸缪,一旦系统部署后再修改,可能就来不及了。
补充:近日公司的另一套CMS系统,已经出现 了上述问题。clob字段直接置于业务表中,现业务表记录已达20余万,查询的速度非常缓慢,被迫采用各种方式来解决。如果当初设计时就考虑到这方面就不会有这样的问题了。
PS:解决方案之一是,可以在Pojo中加入构造函数,参数中包含除clob字段外的所有其它字段,通过select new Pojo(field1,field2,…..) from Pojo的方式来处理。但要注意,fieldx不能为集合类型,只能为基本数据类型或Po类型。如public Pojo(Long id,String name,User usr,Date createDate){}
以上转自:http://www.iteye.com/topic/27917
补充:我们其实现在还有更多的方案解决这个问题 ,例如,把文件文本等存在磁盘,数据库中保存相应的地址。调用的时候直接查询相应地址,根据地址去调用文件。
相关文章推荐
- (转载)对数据表中大字段的处理方式
- 自定义的实体类,接收mybatis查询数据(其中实体类有多余字段处理方式)
- ajax从后台获取数据,返回值为时间和字段太长的处理方式
- Java中基本数据类型的存储方式和相关内存的处理方式
- mysql处理删除自增字段之后下一次插入数据的问题
- 海量积分数据实时排名处理方式介绍一
- Struts2的后台与前台数据交互处理方式的简单总结
- WCF处理不同方式提交的数据的方法
- mysql 大量数据插入(可用于数据添加字段不能添加的情况,因为会copy临时表。这样可以手动分批处理)
- 计算机底层数据的处理方式(汇编后将所有数据都转化为补码二进制数据,所有类型信息都会消失)
- 实际中碰到的一个异构系统之间数据交换的处理方式设计
- ajax方式提交数据时“+”的处理
- php学习笔记(三十)ajax请求和接收参数的实现方式(包括json数据格式的简单处理)
- 找工作——大数据的处理方式
- 0012、node 之简单筛选后台数据以及需要分页时的一种处理方式
- SQL SERVER2000教程-第五章 处理数据 第二十三节 将具有相同字段的记录删除,只留下一条。
- 一次 read by other session 的处理过程--数据走索引需要看索引字段的数据分布情况
- 用悲观并发方式处理数据库并发冲突以保证数据一直性的代码处理方法
- SamplePairing:针对图像处理领域的高效数据增强方式 | PaperDaily #34
- Android通过Get方式提交数据以及乱码处理