您的位置:首页 > 业界新闻

mysql在互联网应用设计和开发中的注意事项

2016-04-11 23:34 549 查看
MySql是开源数据库,在互联网界非常受欢迎,有着极为广泛的应用。这是由MySql的特点和互联网公司的使用场景决定的。首先从MySql的特点上看,MySql简单易用,有着极高的稳定性,同时简单查询时性能极高;MySql的功能很完备,常用的功能几乎都有;开源,功能可自己定制,使用成本低廉;可以支持多种不同用途的存储引擎,以应对不同的业务场景等。同时MySql又是脆弱的,一个复杂sql或者大表join就可能是MySql负载过重,资源耗尽。

互联网公司往往有高并发、大数据量的特点,同时为了在和竞品的竞争中占得先机,产品会不断迭代,新产品不断推出。从技术的角度讲,面临的问题往往很难预测;同时为了拉新用户或者促销,往往有大规模的运营推广活动,例如著名的“双十一”,活动期间访问和交易流量往往是平时的几倍甚至几十倍,如果把系统容量扩展到活动的容量,因为平时的流量没这么大,会造成资源浪费;如果活动期间不扩展系统容量,系统又扛不住突增的流量,从技术的角度讲,希望系统有伸缩能力,既能在活动期间扩容,可以应对突增的流量,又能在活动结束后缩容,不造成资源的浪费,所以互联网公司往往对系统伸缩能力有着执着的追求。

结合MySql的特点和互联网公司的特点,为什么MySql会在互联网界广受欢迎呢,大体有以下几点:

1. 免费:互联网公司内部很多设施需要使用数据库,有些系统会使用多个数据库,如果使用强大的商用数据库,按许可收费,成本高的惊人。国内互联网公司往往走微利模式,创业前几年几乎没有盈利能力,广泛使用虽然强大但使用成本高昂的商用数据库对绝大多数互联网公司是不可承受之重,就算使用也往往只能在某些关键系统中使用;

2. 开源:互联网公司面临的场景和问题很复杂,如果依靠厂商提供技术支持,很难及时处理遇到的问题,影响自身业务的发展。而使用开源的mysql可以根据自身的业务特点和面临的问题,自行开发需要的功能,解决资金的问题;

3. 互联网公司普遍追求横向扩展性:面临高并发、大数据量难题时,互联网公司普遍采用分库分表的方式扩展容量,使用MySql时不需要考虑分库时增加数据库许可的成本;

4. 互联网公司业务一般不复杂,而且读远多于写,刚好是mysql擅长的场景;

在这里提一下MySql的InnoDB存储引擎。从MySql5.5之后,InnoDB成为默认的存储引擎,InnoDB是个相当全面,而且均衡的存储引擎,支持全面的ACID事务特性;引入行级锁,大幅度提升了并发能力;使用MVCC方式也大幅提升并发性能;查询性能与MyIsam相比并不差。

在互联网公司高并发的场景下,对MySql的使用稍有失误就可能让MySql负载增加,速度降低,所以在设计和使用MySql时要比较小心,任何一个无用都可能带来严重的后果。在高并发、大数据量的互联网应用中,系统的扩展性是个至关重要的考量,基于这点考虑,往往把业务逻辑写在容易扩展的应用代码中,因为扩展数据库的难度和代价远远大于扩展应用。只要应用是无状态的,只要往应用集群中增加机器,应用就能线性扩展;而要扩展数据库就就不得不做分库分表了,而做分库分表时不论是数据迁移,还是改造应用层或使用中间件都需要相当大的工作量。所以在设计互联网应用时,在数据库的设计和使用有相应的原则,下面就从核心设计原则和表,字段,索引的设计和使用Sql方面分别描述。

核心设计原则:

不要在数据库里做运算,不要使用存储过程、触发器等(原因:数据库的扩展的能力远不如应用程序强,一旦使用了存储过程、触发器,当数据库遇到瓶颈,想扩展就非常难了。所以,设计互联网应用时,在合适的地方做合适的事情。就让数据库做数据存储和查询吧,至于数据转移、运算、业务逻辑都让应用来做吧)
平衡范式和冗余。在互联网应用中为了优化查询性能,会将必要的信息冗余存放,冗余存储的式违反了第三范式,在提高查询性能的同时也会带来数据一致性的问题,这需要在业务逻辑代码中保证

在互联网应用中,数据库访问频率很高,CPU、内存、IO、网络都是紧缺资源,因此在满足业务的前提下,降低SQL尤其是高频SQL的资源消耗就是个非常重要的优化原则了,在设计表结构时,应该考虑哪些是高频执行的SQL从而采取针对性措施。

库表设计原则:

单表字段数应控制在20个以内。一个表的字段越多,面临的业务场景就会越复杂,面临可能的变化也越多。当查询时,也会因为需要过滤的字段过多,导致更多的IO消耗。这个原则也可以用另外用另外一种形式表达:拆分表中字段来分离冷热数据。大字段和访问频率低的字段都会降低查询的效率,分离冷热数据后,能提示热数据的访问性能,降低IO消耗,提高缓存命中概率
控制表的数据量。当数据量超过千万级别后,即使硬件性能强大,sql执行时间也会下降
选择字段类型时,在满足正确存储业务数据要求的前提下,选择最短的。越小的字段,访问效率越高。不要使用TEXT、BLOB类型;不得不使用TEXT、BLOB类型时,拆分到单独表中;用DECIMAL代替FLOAT和DOUBLE存储精确浮点数;使用整数替代浮点数:比如用分为单位表示以元为单位的金额;使用数字或ENUM代替字符或字符串
如果可能的话所有字段均定义为not null,因为null值使索引失效。对于数据量比较大的表而言,索引失效时查询将是灾难性的低效

索引对于性能来说非常关键,尤其是数据量非常越大时。查询时使用到索引可以减少查询时扫描的数据量、避免排序、将随机IO转为顺序IO。代价就是修改或删除数据时,索引需要重新排序,降低了性能。索引还能使查询条件命中的索引作为行锁的条件

索引设计使用原则:

将索引建立在高区分度字段上。索引是按照字段内容排序的,如果字段值区分度不高,在索引中将有很多大段的相同值,用这样的索引查询时,过滤效果非常不明显,所以不要在区分度低的字段上创建索引。字段值区分度高时可以根据查询值迅速定位查询结果,提示查询效率
索引应该建立在短字段上。尽量不要建在长字符串上,如果不可避免,可以选择字符串的开头几位。建立索引时要把字段内容保存到索引中,所以字段越长,索引占得硬盘空间也就越大,查询时消耗的硬盘IO资源也就越大,耗时越长
创建复合索引时索引的列顺序至关重要。查询有多个条件时,适合使用复合索引查询。如果有多种查询组合条件,复合索引建立得当的话,复合索引可以复用。建立复合索引时,自个字段的顺序仍然优先按照区分度,其次再考虑索引复用
不要在索引列上进行数学运算、函数运算(会使索引失效)
单张表中索引数量不超过5个,单个索引中的字段数不超过5个,通常将选择性最高的列放在最前面。如果一个表的索引太多,最可能的原因是开始时这个表担负了太多的职责,考虑将此表的职责拆分。

SQL使用原则:

拒绝大sql,尽可能不做表之间的join操作

<code class="hljs haml has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">原因:
-<span class="ruby" style="box-sizing: border-box;"> mysql更擅长简单查询,尤其是单表主键或二级索引查询;mysql一条sql只能使用一个cpu,有大表join的情况下,性能下降明显
</span> -<span class="ruby" style="box-sizing: border-box;"> 大sql不仅慢,而且会大幅度降低数据库的并发能力,甚至拖垮数据库
</span> -<span class="ruby" style="box-sizing: border-box;"> 使用多条简单sql,使缓存命中率更高,还可以使用多核
</span> -<span class="ruby" style="box-sizing: border-box;"> 高并发场景下,不要使用两个或以上的表join</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>


限制返回结果条数,否则返回满足条件的所有记录。大多数情况下这是不必要的,应用在处理返回的大量结果时可能崩溃
不要使用select *,只查询需要的列

a、select * 消耗了更多的cpu,内存,io,网络资源;

b、使用具体字段除了减少资源消耗,还减小了表增加字段时的影响;
避免关联子查询。mysql的关联子查询实现非常糟糕,除非有非常高深的优化功力,否则不要写关联子查询。
避免负向查询,不要使用NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、 NOT LIKE等。不能使用索引,导致全表扫描,效率低下。
避免使用count。除非是非常小的表,否则尽可能使用冗余字段计数或其他方式。
分页时避免传统的limit offset, size方式分页。这种方式随着偏移量大,性能越来越差,可以考虑把分页转换成条件查询。
使用in代替or,in的值不超过200个。IN的效率(O(log n))比OR的效率(O(n))高很多。
使用预编译的sql。使用预编译的sql不仅能防sql注入攻击,还可以避免mysql服务器编译的开销。

本文的内容相当比例来自附件的《MySql36条军规》,并结合公司目前现状做了补充和删减。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: