一些应用,在表结构的设计上使用了text或者blob的字段;其中一个应用,对blob字段的依赖非常的严重,查询和更新的频率也是非常的高,单表的存储空间已经达到了近100G,这个时候,应用其实已经被数据库绑死了,任何应用或者查询逻辑的变更几乎成为不可能;
为了清楚大字段对性能的影响,我们必须要知道innodb存储引擎在底层对行的处理方式:
- 在5.1中,innodb存储引擎的默认的行格式为compact(redundant为兼容以前的版本),对于blob,text,varchar(8099)这样的大字段,innodb只会存放前768字节在数据页中,而剩余的数据则会存储在溢出段中(发生溢出情况的时候适用);
- innodb的块大小默认为16kb,由于innodb存储引擎表为索引组织表,树底层的叶子节点为一双向链表,因此每个页中至少应该有两行记录,这就决定了innodb在存储一行数据的时候不能够超过8k(8098字节);
- 使用了blob数据类型,是不是一定就会存放在溢出段中?通常我们认为blob,clob这类的大对象的存储会把数据存放在数据页之外,其实不然,关键点还是要看一个page中到底能否存放两行数据,blob可以完全存放在数据页中(单行长度没有超过8098字节),而varchar类型的也有可能存放在溢出页中(单行长度超过8098字节,前768字节存放在数据页中);
- 5.1中的innodb_plugin引入了新的文件格式:barracuda(将compact和redundant合称为antelope),该文件格式拥有新的两种行格式:compressed和dynamic,两种格式对blob字段采用完全溢出的方式,数据页中只存放20字节,其余的都存放在溢出段中:
- mysql在操作数据的时候,以page为单位,不管是更新,插入,删除一行数据,都需要将那行数据所在的page读到内存中,然后在进行操作,这样就存在一个命中率的问题,如果一个page中能够相对的存放足够多的行,那么命中率就会相对高一些,性能就会有提升;
有了上面的知识点,我们一起看看该应用的特点,表结构:
CREATE TABLE `xx_msg` ( `col_user` VARCHAR(64) NOT NULL, `col_smallint` SMALLINT(6) NOT NULL, `col_lob` longblob, `gmt_create` datetime DEFAULT NULL, `gmt_modified` datetime DEFAULT NULL, PRIMARY KEY (`xxx`) ) ENGINE=InnoDB DEFAULT CHARSET=gbk
col_lob为blob字段,用于存放该用户的所有的消息,其平均长度在2.4kb左右,该表中其他剩余的字段则是非常的小,大致在60字节左右
SELECT avg(LENGTH(col_clob)) FROM (SELECT * fromxxx_msg LIMIT 30000)a; | 2473.8472 |
该表的应用场景包括:
1) select col_user ,col_smallint,DATE_FORMAT(gmt_modified,’%Y-%m-%d’) from xx_msg;
2) update xx_msg set gmt_modified=’2012-03-31 23:16:30′,col_smallint=1,col_lob=’xxx’ where col_user=’xxx’;
3) select col_smallint from xx_msg where user=’xxx’;
可以看到由于单行的平均长度(2.5k)还远小于一个innodb page的size(16k)(当然也有存在超过8k的行),也就是知识点三中提到的,blob并不会存放到溢出段中,而是存放到数据段中去,innodb能够将一行的所有列(包括longlob)存储在数据页中:
在知识点五中,mysql的io以page为单位,因此不必要的数据(大字段)也会随着需要操作的数据一同被读取到内存中来,这样带来的问题由于大字段会占用较大的内存(相比其他小字段),使得内存利用率较差,造成更多的随机读取。
从上面的分析来看,我们已经看到性能的瓶颈在于由于大字段存放在数据页中,造成了内存利用较差,带来过多的随机读,那怎么来优化掉这个大字段的影响:
一.压缩:
在知识点四中,innodb提供了barracuda文件格式,将大字段完全存放在溢出段中,数据段中只存放20个字节,这样就大大的减小了数据页的空间占用,使得一个数据页能够存放更多的数据行,也就提高了内存的命中率(对于本实例,大多数行的长度并没有超过8k,所以优化的幅度有限);如果对溢出段的数据进行压缩,那么在空间使用上也会大大的降低,具体的的压缩比率可以设置key_blok_size来实现。
二.拆分:
将主表拆分为一对一的两个关联表:
CREATE TABLE `xx_msg` ( `col_user` VARCHAR(64) NOT NULL, `col_smallint` SMALLINT(6) NOT NULL, `gmt_create` datetime DEFAULT NULL, `gmt_modified` datetime DEFAULT NULL, PRIMARY KEY (`xxx`) ) ENGINE=InnoDB DEFAULT CHARSET=gbk; CREATE TABLE `xx_msg_lob` ( `col_user` VARCHAR(64) NOT NULL, `col_lob` longblob, PRIMARY KEY (`xxx`) ) ENGINE=InnoDB DEFAULT CHARSET=gbk
xx_msg表由于将大字段单独放到另外一张表后,单行长度变的非常的小,page的行密度相比原来的表大很多,这样就能够缓存足够多的行,表上的多个select由于buffer pool的高命中率而受益;应用程序需要额外维护的是一张大字段的子表;
三.覆盖索引:
在上面的两个查询当中,都是查询表中的小字段,由于老的方案需要全表或者根据主键来定位表中的数据,但是还是以page为单位进行操作,blob字段存在还是会导致buffer pool命中率的下降,如果通过覆盖索引来优化上面的两个查询,索引和原表结构分开,从访问密度较小的数据页改为访问密度很大的索引页,随机io转换为顺序io,同时内存命中率大大提升;额外的开销为数据库多维护一个索引的代价;
alter table xx_msg add index ind_msg(col_user ,col_smallint,gmt_modified);
对于查询一,原来的执行计划为走全表扫描,现在通过全索引扫描来完成查询;
对于查询二,原来的执行计划为走主键PK来定位数据,现在该走覆盖索引ind_msg完成查询;
注意上面的两个查询为了稳固执行计划,需要在sql执行中加入hint提示符来强制sql通过索引来完成查询;
总结:上面三种思路来优化大字段,其核心思想还是让单个page能够存放足够多的行,不断的提示内存的命中率,尽管方法不同,但条条大路通罗马,从数据库底层存储的原理出发,能够更深刻的优化数据库,扬长避短,达到意想不到的效果。
转子:http://hidba.org/?p=551
相关推荐
虽然使用`IFNULL()`函数可以提供数据完整性,但要注意这可能会对查询性能产生影响。如果`IFNULL()`涉及的字段是索引的一部分,查询性能可能会下降,因为数据库需要检查更多的行来确定是否需要应用默认值。在这种...
索引的长度也会对数据库的性能产生影响。索引长度短的查询起来就快,但并非越短越好。过短会使得数据查询不精确,而过长查询效率又得不到有效提升,还占用存储空间。 优化字段存储 除了建立索引外,还可以通过优化...
总结来说,MySQL的时区设置对查询效率有直接影响,尤其是在多线程并发和时间字段频繁使用的场景下。优化时区设置可以减少不必要的时区转换,从而提高查询性能。对于高并发和时间敏感的业务,建议根据实际需求设定...
字段字符集编码对性能的影响不容忽视。不同的字符集可能会导致不同的存储需求和处理速度。例如,如果一个JOIN操作涉及到两个字段,它们在不同的表中但使用了不同的字符集,那么JOIN操作可能会变得非常慢,因为数据库...
8. **优化与性能**:大量图片的转换可能会对数据库性能产生影响,因此需要考虑批量处理、缓存机制或异步处理等优化策略。 9. **安全性**:确保在读取和写入文件时遵循安全最佳实践,防止数据泄露或恶意攻击。 10. ...
* 性能问题:交叉查询可能会对数据库性能产生影响,因此需要对数据库进行优化和维护。 * 数据一致性:交叉查询需要确保数据的一致性,以免出现数据不一致的问题。 * 安全问题:交叉查询需要确保数据库的安全,以免...
需要注意的是,`ORDER BY`操作可能会对查询性能产生影响,特别是在处理大型数据集时。因此,如果可能,应考虑创建相应的索引来优化排序过程。索引可以在数据库中预先组织数据,使其能更快地根据指定的列进行查找和...
特别是在大型企业级应用中,由于各种原因(如数据导入错误、系统故障等),数据库表中可能会出现大量的重复记录,这对数据的准确性和系统的性能都会产生负面影响。因此,掌握如何有效地识别并删除这些重复记录显得尤...
例如,当需要对某个字段进行查询时,如果该字段已经建立了索引,那么可以采用范围查询等方法来提高查询效率。 综合以上分析,我们可以得出以下几点重要的SQL Server数据库查询性能优化策略: 1. 利用过程缓存,...
- **索引的使用**:索引的存在和选择性极大地影响连接性能。如果一个表的连接字段上有索引,那么这个索引通常会被用来加速连接。 - **数据量**:如果一个表的记录数远大于另一个,通常会选择小表作为驱动表,以减少...
另一种方法是通过查询现有最大`sessionid`并加1来获取新的`sessionid`,但这会增加数据库的查询负担,影响性能。因此,第一种方法通常更优,因为它减少了对数据库的交互次数。 数据库性能优化是一个广泛的领域,...
由于数据库查询效率直接影响到系统的响应速度和用户体验,对查询语句的优化显得至关重要。 1. 避免在where子句中对字段进行null值判断是优化查询的一个重要方面。在SQL Server中,null值的比较会导致查询无法利用...
值得注意的是,这样的设计可能会导致数据冗余,因为`man`表中的`man_id`字段在`zw`表中重复出现,这可能对数据库的性能和维护性产生影响。在设计数据库时,考虑使用外键和多对多关系表可能会更合适。例如,可以创建...
- **子查询**: `(select peopleid from people group by peopleid having count(peopleid) > 1)` 这部分首先从`people`表中选择`peopleid`字段,然后使用`GROUP BY`对`peopleid`进行分组,计算每组的`peopleid`数量...
根据系统负载和硬件配置,适当调整数据库的配置参数,如缓存大小、并发连接数等,也能对查询性能产生积极影响。 总之,SQL查询优化是一个涉及多个层面的综合过程,需要结合具体的应用场景和数据库系统特性,通过...
尽管前缀查询非常强大且有用,但在某些情况下可能会对性能产生负面影响,尤其是处理大量数据时。为了优化前缀查询的性能,可以采取以下措施: 1. **使用缓存**:对于频繁执行的查询,可以在应用程序级别缓存结果,...
在数据库管理领域,触发器(Trigger)是一种存储过程,它被设计用于响应特定类型的对一个表的数据的操作(如INSERT、UPDATE或DELETE),并自动执行预定义的SQL语句。触发器是实现数据库完整性、安全性和业务规则的...
设置得过小可能会再次遇到截断问题,而设置得过大又可能对性能产生影响或增加内存消耗。因此,在实际开发过程中,需要在保证数据完整性与系统性能之间做出权衡。 此外,根据文档内容,由于文档可能是通过OCR扫描...
数据表的设计同样会对查询性能产生重要影响。字符类型的选择需要根据存储数据的实际情况来确定,固定长度的数据类型如char、nchar和binary适合存储长度一致的数据,而可变长度的数据类型varchar、nvarchar和...
5. **调整数据库配置**:根据实际情况调整数据库的相关配置参数,比如缓存大小、并发控制策略等,也能对查询性能产生积极影响。 6. **定期维护**:定期对数据库进行维护,如重建索引、清理冗余数据等,也是保持查询...