1. 优化SQL前端
1)经过show status了解各类sql的执行频率mysql
show status like 'Com_%'
了解 Com_select,Com_insert 的执行次数
2) 经过Explain分析低效的sql语句
3) 创建合适的索引
4) 经过show status like 'Handler_%'查看索引的使用状况
handler_read_key:根据索引读取行的请求数。若是该值很大,说明你的查询和表都创建了很好的索引,代表索引效率的很高
Handler_read_rnd_key:根据固定位置读取行的请求数。若是你执行不少须要排序的查询,该值会很高。你可能有不少须要完整表扫描的查询,或者你使用了不正确的索引用来多表查询。web
Handler read rnd next:从数据文件中读取行的请求数。若是你在扫描不少表,该值会很大。一般状况下这意味着你的表没有作好索引,或者你的查询语句没有使用好索引字段。算法
5) 按期分析表和检查表
analyze table test_table和check table test_table
而后查看Msg_text字段的值是不是ok
6)按期优化表 optimize table test_table
若是对表的可变字段varchar blob,text等进行了不少更改, 则应用OPTIMIZE优化。sql
在多数的设置中,您根本不须要运行OPTIMIZE TABLE。即便您对可变长度的行进行了大量的更新,您也不须要常常运行,每周一次或每个月一次便可,只对特定的表运行。
OPTIMIZE TABLE只对MyISAM, BDB和InnoDB表起做用。
对于MyISAM表,OPTIMIZE TABLE按以下方式操做:
若是表已经删除或分解了行,则修复表。
若是未对索引页进行分类,则进行分类。
若是表的统计数据没有更新(而且经过对索引进行分类不能实现修复),则进行更新。
7) 优化 order by orgroup by等数据库
详细内容:SQL优化大全缓存
2. 优化数据库对象安全
1)选择表合适存储引擎:服务器
MyISAM: 应用时以读和插入操做为主,只有少许的更新和删除,而且对事务的完整性,并发性要求不是很高的.数据结构
Innodb: 事务处理,以及并发条件下要求数据的一致性。除了插入和查询外,包括不少的更新和删除。(Innodb有效地下降删除和更新致使的锁定)。对于支持事务的InnoDB类型的表来讲,影响速度的主要缘由是AUTOCOMMIT默认设置是打开的,并且程序没有显式调用BEGIN 开始事务,致使每插入一条都自动提交,严重影响了速度。能够在执行sql前调用begin,多条sql造成一个事物(即便autocommit打开也能够),将大大提升性能。
Memory:数据保存在RAM,快速访问数据。要求表不能太大或者对MySQL异常终止后不用恢复数据的
Merge:
2)优化表的数据类型,选择合适的数据类型:
原则:更小一般更好,简单就好,全部字段都得有默认值,尽可能避免null:
例如:数据库表设计时候更小的占磁盘空间尽量使用更小的整数类型.(mediumint就比int更合适)
好比时间字段:datetime和timestamp, datetime占用8个字节,而timestamp占用4个字节,只用了一半,而timestamp表示的范围是1970—2037适合作更新时间
MySQL能够很好的支持大数据量的存取,可是通常说来,数据库中的表越小,在它上面执行的查询也就会越快。所以,在建立表的时候,为了得到更好的性能,咱们能够将表中字段的宽度设得尽量小。例如,在定义邮政编码这个字段时,若是将其设置为CHAR(255),显然给数据库增长了没必要要的空间,甚至使用VARCHAR这种类型也是多余的,由于CHAR(6)就能够很好的完成任务了。一样的,若是能够的话,咱们应该使用MEDIUMINT而不是BIGIN来定义整型字段。
另一个提升效率的方法是在可能的状况下,应该尽可能把字段设置为NOT NULL,这样在未来执行查询的时候,数据库不用去比较NULL值。
对于某些文本字段,例如“省份”或者“性别”,咱们能够将它们定义为ENUM类型。由于在MySQL中,ENUM类型被看成数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,咱们又能够提升数据库的性能。
3) 字符串数据类型:char,varchar,text选择区别
(1)长度的区别,char范围是0~255,varchar最长是64k,可是注意这里的64k是整个row的长度, 要考虑到其它的column,还有若是存在not null的时候也会占用一位,对不一样的字符集,有效长度还不同,好比utf8的,最多21845,还要除去别的column,可是varchar在通常 状况下存储都够用了。若是遇到了大文本,考虑使用text,最大能到4G。
(2) 效率来讲基本是char>varchar>text,可是若是使用的是Innodb引擎的话,推荐使用varchar代替
(3)默认值 charchar和varchar能够有默认值,text不能指定默认值
4)MySQL中float数据类型的问题
(1) .FLOAT或DOUBLE列与具备数值类型的数值进行比较,不能使用等式(=)比较.这个是由于浮点数精度的问题,会产生偏差。
(2)对货币等对精度敏感的数据,应该用定点数表示或存储
数据库选择合适的数据类型存储仍是颇有必要的,对性能有必定影响。这里在零碎记录两笔,对于int类型的,若是不须要存取负值,最好加上unsigned;对于常常出如今where语句中的字段,考虑加索引,整型的尤为适合加索引。
5)在InnoDB数据表设计中,咱们须要注意几点:
1. 显式的定义一个 INT 类型自增字段的主键,这个字段能够仅用于作主键,不作其余用途
2. 若是不显式定义主键的话,可能会致使InnoDB每次都须要对新数据行进行排序,严重损害性能
3. 尽可能保证不对主键字段进行更新修改,防止主键字段发生变化,引起数据存储碎片,下降IO性能
4. 若是须要对主键字段进行更新,请将该字段转变成一个惟一索引约束字段,另外建立一个没有其余业务意义的自增字段作主键
5. 主键字段类型尽量小,能用SMALLINT就不用INT,能用INT就不用BIGINT
6. 主键字段放在数据表的第一顺序
3. 优化索引
索引是提升数据库性能的经常使用方法,它能够令数据库服务器以比没有索引快得多的速度检索特定的行,尤为是在查询语句当中包含有MAX(), MIN()和ORDERBY这些命令的时候,性能提升更为明显.
那该对哪些字段创建索引呢?通常说来,索引应创建在那些将用于JOIN, WHERE判断和ORDER BY排序的字段上。尽可能不要对数据库中某个含有大量重复的值的字段创建索引。对于一个ENUM类型的字段来讲,出现大量重复值是颇有可能的状况,例如customerinfo中的“province”..字段,在这样的字段上创建索引将不会有什么帮助;相反,还有可能下降数据库的性能。咱们在建立表的时候能够同时建立合适的索引,也可使用ALTER TABLE或CREATE INDEX在之后建立索引
1). 普通索引
普通索引(由关键字KEY或INDEX定义的索引)的惟一任务是加快对数据的访问速度。所以,应该只为那些最常常出如今查询条件(WHERE column = …)或排序条件(ORDER BY column)中的数据列建立索引。只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如一个整数类型的数据列)来建立索引。
2). 惟一索引
普通索引容许被索引的数据列包含重复的值。好比说,由于人有可能同名,因此同一个姓名在同一个”员工我的资料”数据表里可能出现两次或更屡次。
若是能肯定某个数据列将只包含彼此各不相同的值,在为这个数据列建立索引的时候就应该用关键字UNIQUE把它定义为一个惟一索引。这么作的好处:一是简 化了MySQL对这个索引的管理工做,这个索引也所以而变得更有效率;二是MySQL会在有新记录插入数据表时,自动检查新记录的这个字段的值是否已经在 某个记录的这个字段里出现过了;若是是,MySQL将拒绝插入那条新记录。也就是说,惟一索引能够保证数据记录的惟一性。事实上,在许多场合,人们建立惟 一索引的目的每每不是为了提升访问速度,而只是为了不数据出现重复。
3). 主索引
在前面已经反复屡次强调过:必须为主键字段建立一个索引,这个索引就是所谓的”主索引”。主索引与惟一索引的惟一区别是:前者在定义时使用的关键字是PRIMARY而不是UNIQUE。
4). 外键索引
若是为某个外键字段定义了一个外键约束条件,MySQL就会定义一个内部索引来帮助本身以最有效率的方式去管理和使用外键约束条件。
5). 复合索引
索引能够覆盖多个数据列,如像INDEX(columnA, columnB)索引。这种索引的特色是MySQL能够有选择地使用一个这样的索引。若是查询操做只须要用到columnA数据列上的一个索引,就可使 用复合索引INDEX(columnA, columnB)。不过,这种用法仅适用于在复合索引中排列在前的数据列组合。好比说,INDEX(A, B, C)能够当作A或(A, B)的索引来使用,但不能当作B、C或(B, C)的索引来使用。
4. 表锁的问题
跟性能相关的最重要的区别就是 MyISAM 和 InnoDB 实现的锁机制不同! MyISAM 使用的是表锁, 而 InnoDB实现的是行锁。
1) MyISAM为表级锁
因为MyISAM写进程优先得到锁,使得读锁请求靠后等待队列。不只如此,即便读请求先到锁等待队列,写请求后 到,写锁也会插到读锁请求以前!这是由于MySQL认为写请求通常比读请求要重要。
若是在大量更新操做的状况下,使得很难得到读锁。从而形成阻塞。
因此MyIsam不适合作大量更新操做的缘由
2 )INNODB的行锁是基于索引实现,若是不经过索引访问数据,Innodb会使用表锁
表级锁更适合以查询为主,只有少许按索引条件更新数据的应用。
行级锁更适合于有大量按索引条件并发更新少许不一样数据,同时又并发查询。由于只锁定要操做的行, 因此能够多个线程同时操做不一样的行(只要不操做其余线程已经锁定的行)。
5. MySQL server服务器配置优化
1)使用show variables 了解服务器参数
2)show status 了解服务器运行状态,如锁等待状况,当前链接数等
3)影响mysql性能的重要参数:
key_buffer_size设置索引块的缓存大小:key_buffer_size是对MyISAM表性能影响最大的一个参数
经过:
mysql> show global status like 'key_read%';
+-------------------+------------+
| Variable_name | Value |
+-------------------+------------+
| Key_read_requests | 3465117712 |
| Key_reads | 624 |
+-------------------+------------+
Key_read_requests:从缓存读取索引的请求次数。
Key_reads:从磁盘读取索引的请求次数。
一般人们认为Key_read_requests / Key_reads越大越好
须要适当加大key_buffer_size
table_cache数据库打开表的缓存数量 ,每一个链接进来,都会至少打开一个表缓存。所以
table_cache和max_connections有关, 例如 对于200个并行运行的链接,应该让表的缓存至少是200 *N
N 是能够执行查询的一个链接中的表的最大数
4) 还有innodb_buffer_pool_size等innodb参数的设置
6. 磁盘IO优化
对于咱们数据库调优来讲,磁盘I/O优化是数一数二的调优重点,咱们都知道木桶原理,短板绝对总体的好坏,而数据库系统中这个短板正是因为咱们 使用的硬件设备里最弱的磁盘所致使。不少时候,咱们会发现系统中I/O累得要死,而CPU却在那里空闲等待,主要是因为I/O执行响应时间太长,处理读写 的速度远远赶落后于CPU的处理速度,这时咱们会尽量的让操做放到内存中进行,由磁盘与CPU的关系,转变成内存与CPU的关系。可是,咱们始终不能回 避磁盘I/O的弱点,优化是必须的。
磁盘搜索是巨大的性能瓶颈。当数据量变得很是大以至于缓存性能变得不可能有效时,该问题变得更加明显。对于大数据库,其中你或多或少地随机访问数据, 你能够确 信对读取操做须要至少一次硬盘搜索,写操做须要屡次硬盘搜索。要想使该问题最小化, 应使用搜索次数较少的磁盘。
1)使用磁盘阵列 RAID (廉价磁盘冗余阵列)
RAID就是按照必定的策略将数据分布到若干物理磁盘上,这样不只加强了数据存储的可靠性,并且提升数 据读写的性能 (RAID有不能的级别)
1) 读写很频繁的,可靠性要求也很高的,最好RAID 10
2) 数据读很频繁,写相对较少的,对可靠性必定要求的,选择RAID 5
3) 数据读写都很频繁,可是可靠性要求不高的能够选择RAID 0
2) 使用符号连接 分布I/O
MYSQL在默认的状况下,数据库和数据表都存放在参数datadir定义的目录下,这样若是不使用RAID或者逻辑卷,全部的数据都存放在一个磁盘设备上,没法发挥多磁盘并 行读写的优点。
能够将表和数据库从数据库目录移动到其它的位置而且用指向新位置的符号连接进行替换。推荐的方法只须要将数据库经过符号连接指到不一样的磁盘。符号连接表仅做为是 最后的办法。
符号连接一个数据库的方法是,首先在一些有空闲空间的硬盘上建立一个目录,而后从 MySQL 数据目录中建立它的一个符号连接。
例如:
[plain] view plain copy
注意:只有 MyISAM 表彻底支持符号连接。对于其它表类型,若是试图在操做系统 中的文件上用前面的任何语句使用符号连接,可能会出现奇怪的问题。
对于 MyISAM 表的符号连接的处理以下:
1. 在数据目录指,必定会有表定义文件、数据文件和索引文件。数据文件和索引文件可 以移到别处和在数据目录中符号连接替代。表定义文件不能进行符号连接替换。
2. 能够分别经过符号连接将数据文件和索引文件指到不一样的目录。
3. 若是 mysqld 没有运行,符号连接能够从服务器命令行使用 ln -s 手动完成。一样,经过使用 DATA DIRECTORY 和 INDEX DIRECTORY 选项建立表,你能够指示运行的 MySQL 服务器执行符号连接。
4. myisamchk 不用数据文件或索引文件替换符号连接。它直接工做在符号连接指向的文件。任何临时文件建立在数据文件或索引文件所处的目录中。
5. 注释:当你删掉一个表时,若是该表使用了符号连接,符号连接和该符号连接指向的 文件都被删除掉。这就是你不该以系统 root 用户运行 mysqld 或容许系统用户对 MySQL数据库目录有写访问权限的缘由。
6. 若是你用 ALTER TABLE ... RENAME 重命名一个表而且不将表移到另外一个数据库,数据库目录中的符号连接被从新命名为一个新名字而且数据文件和索引文件也相应地从新命名。
7. 若是你用 ALTER TABLE ... RENAME 移动一个表到另外一个数据库,表移动到另外一个数据库目录。旧的符号连接和其所指向的文件被删除。换句话说,新表再也不被连接。
8. 若是不使用符号连接,你应对 mysqld 使用 --skip-symbolic-links 选项以确保没有人可以使用 mysqld 来删除或从新命名数据目录以外的文件。
表符号连接还不支持如下操做:
1. ALTER TABLE 忽略 DATA DIRECTORY 和 INDEX DIRECTORY 表选项。
2. BACKUP TABLE 和 RESTORE TABLE 不考虑符号连接。
3. .frm 文件必须毫不能是一个符号连接(如前面所述,只有数据和索引文件能够是符连接)。若是试图这样作(例如,生成符号连接)会产生不正确的结果。
3) 禁止操做系统更新文件的atime属性
7. 应用优化
1 )使用链接池
对于访问数据库来讲,创建链接的代价比较昂贵,所以,咱们有必要创建 " 链接池 " 以提升访问的性能。咱们能够把链接看成对象或者设备,池中又有许多已经创建的链接,访 问原本须要与数据库的链接的地方,都改成和池相连,池临时分配链接供访问使用,结果返 回后,访问将链接交还。
2)减小对mysql的访问,使用mem缓存等
3)负载均衡,复制分流查询操做
利用mysql的主从复制,分流更新操做和查询操做
1), 建立复制帐号:Gran replication slave on *.* to 'rel'@'10.0.1.2' identified by '123456'
2), 修改主服务器的配置my.conf 开启binlog和设置server-id
3), 将主服务器的数据一致性恢复到从服务器,保证将要复制的数据时一只的,不然出问题
4), 在从服务器上修改配置my.conf
server-id=2
master-host=10.0.1.3
master-user='rel'
master-password='123456'
master-port='3306'
5), 从服务器启动slave线程: start slave
show processlist 查看。
4) 分布式cluster 数据库架构
8. 分库分表
1)水平划分
若是某个表的数据太多,预期有上千条甚至上亿以上,咱们能够化整为0:拆表。
这里就涉及到拆表的算法:
记录日志的表,也能够按周或者按月来拆。
记录用户信息的表,按用户id的hash算法来拆。
2)垂直拆分
若是表记录数并很少,可能也就二、3万条,可是字段却很长,表占用空间很大,检索表时须要执行大量I/O,严重下降了性能。这个时候须要把大的字段拆分到另外一个表,而且该表与原表是一对一的关系。
分库解决方案原则:
n安全性拆分:
将高安全性数据与低安全性数据分库,这样的好处第一是便于维护,第二是高安全性数据的数据库参数配置能够以安全优先,而低安全性数据的参数配置以性能优先。参见运维优化相关部分。
n基于业务逻辑拆分
1)根据数据表的内容构成,业务逻辑拆分,便于平常维护和前端调用。
2)基于业务逻辑拆分,能够减小前端应用请求发送到不一样数据库服务器的频次,从而减小连接开销。
3)基于业务逻辑拆分,可保留部分数据关联,前端web工程师可在限度范围内执行关联查询。
n基于负载压力拆分
1)基于负载压力对数据结构拆分,便于直接将负载分担给不一样的服务器。
2)基于负载压力拆分,可能拆分后的数据库包含不一样业务类型的数据表,平常维护会有必定的烦恼。
n混合拆分组合
1)基于安全与业务拆分为数据库实例,可是可使用不一样端口放在同一个服务器上。
2)基于负载能够拆分为更多数据库实例分布在不一样数据库上
如:
基于安全拆分出A数据库实例,
基于业务拆分出B,C数据库实例,
数据库存在较高负载,基于负载拆分为C1,C2,C3,C4等实例。
数据库服务器彻底能够作到 A+B+C1 为一台,C2,C3,C4各单独一台。
分表方案解决原则
一、通常数据量过大或者访问压力过大的数据表须要切分
二、表的字段不宜过多。
n纵向分表
单数据表字段过多,可将频繁更新的整数数据与非频繁更新的字符串数据切分
范例user表 ,我的简介,地址,QQ号,联系方式,头像 这些字段为字符串类型,更新请求少; 最后登陆时间,在线时常,访问次数,信件数这些字段为整数型字段,更新频繁,能够将后面这些更新频繁的字段独立拆出一张数据表,表内容变少,索引结构变少,读写请求变快。
n横向切表
1)等分切表,如哈希切表或其余基于对某数字取余的切表。等分切表的优势是负载很方便的分布到不一样服务器;缺点是当容量继续增长时没法方便的扩容,须要从新进行数据的切分或转表。并且一些关键主键不易处理。
2)递增切表,好比每1kw用户开一个新表,优势是能够适应数据的自增趋势;缺点是每每新数据负载高,压力分配不平均。
3)日期切表,适用于日志记录式数据,优缺点等同于递增切表。
4)我的倾向于递增切表,具体根据应用场景决定。
n热点数据分表
1)将数据量较大的数据表中将读写频繁的数据抽取出来,造成热点数据表。一般一个庞大数据表常常被读写的内容每每具备必定的集中性,若是这些集中数据单独处理,就会极大减小总体系统的负载。
2)热点数据表与旧有数据关系
能够是一张冗余表,即该表数据丢失不会妨碍使用,因源数据仍存在于旧有结构中。优势是安全性高,维护方便,缺点是写压力不能分担,仍须要同步写回原系统。
能够是非冗余表,即热点数据的内容原有结构再也不保存,优势是读写效率所有优化;缺点是当热点数据发生变化时,维护量较大。
具体方案选择须要根据读写比例决定,在读频率远高于写频率状况下,优先考虑冗余表方案。
3)热点数据表能够用单独的优化的硬件存储,好比昂贵的闪存卡或大内存系统。
4)热点数据表的重要指标
热点数据的定义须要根据业务模式自行制定策略,常见策略为,按照最新的操做时间;按照内容丰富度等等。
数据规模,好比从1000万条数据,抽取出100万条热点数据。
热点命中率,好比查询10次,多少次命中在热点数据内。
理论上,数据规模越小,热点命中率越高,说明效果越好。须要根据业务自行评估。
5)热点数据表的动态维护
加载热点数据方案选择
定时从旧有数据结构中按照新的策略获取
在从旧有数据结构读取时动态加载到热点数据
剔除热点数据方案选择
基于特定策略,定时将热点数据中访问频次较少的数据剔除
如热点数据是冗余表,则直接删除便可,如不是冗余表,须要回写给旧有数据结构。
6)一般,热点数据每每是基于缓存或者key-value方案冗余存储,因此这里提到的热点数据表,其实更可能是理解思路,用到的场合可能并很少….
9. 反范式设计(冗余结构设计)
反范式设计的概念
无外键,无连表查询。
便于分布式设计,容许适度冗余,为了容量扩展容许适度开销。
基于业务自由优化,基于i/o 或查询设计,无须遵循范式结构设计。
冗余结构设计所面临的典型场景
原有展示程序涉及多个表的查询,但愿精简查询程序
数据表拆分每每基于主键,而原有数据表每每存在非基于主键的关键查询,没法在分表结构中完成。
存在较多数据统计需求(count, sum等),效率低下。
冗余设计方案
1)基于展示的冗余设计
为了简化展示程序,在一些数据表中每每存在冗余字段:
举例,信息表message,存在字段fromuid,touid,msg,sendtime四个字段,其中touid+sendtime是复合索引。存在查询为select * from message where touid=$uid order by sendtime desc limit 0,30;
展现程序须要显示发送者姓名,此时一般会在message表中增长字段fromusername,甚至有的会增长fromusersex,从而无需连表查询直接输出信息的发送者姓名和性别。这就是一种简单的,为了不连表查询而使用的冗余字段设计。
2)基于展示的冗余设计
涉及分表操做后,一些常见的索引查询可能须要跨表,带来没必要要的麻烦。确认查询请求远大于写入请求时,应设置便于查询项的冗余表。
冗余表要点:
数据一致性,简单说,同增,同删,同更新。
能够作全冗余,或者只作主键关联的冗余,好比经过用户名查询uid,再基于uid查询源表。
实战范例1
用户分表,将用户库分红若干数据表
基于用户名的查询和基于uid的查询都是高并发请求。
用户分表基于uid分红数据表,同时基于用户名作对应冗余表。
若是容许多方式登录,能够有以下设计方法
nuid,passwd,用户信息等等,主数据表,基于uid分表
nukey,ukeytype,uid基于ukey分表,便于用户登录的查询。分解成以下两个SQL。
uselect uid from ulist_key_13 where ukey=’$username’ and ukeytype=‘login’;
uselect * from ulist_uid_23 where uid=$uid and passwd=’$passwd’;
nukeytype定义用户的登录依据,好比用户名,手机号,邮件地址,网站昵称等。Ukey+ukeytype 必须惟一。
n此种方式须要登录密码统一,对于第三方connect接入模式,能够经过引伸额外字段完成。
实战范例2:用户游戏积分排名
表结构uid,gameid,score参见前文实时积分排行。表内容巨大,须要拆表。
需求1:基于游戏id查询积分排行
需求2:基于用户id查询游戏积分记录
解决方案:创建彻底相同的两套表结构,其一以uid为拆表主键,其二以gameid为拆表主键,用户提交积分时,向两个数据结构同时提交。
实战范例3:全冗余查询结构
主信息表仅包括 主键及备注memo字段(text类型),只支持主键查询,能够基于主键拆表。因此须要展示和存储的内容均在memo字段重体现。
对每个查询条件,创建查询冗余表,以查询条件字段为主键,以主信息表主键id为内容。
平常查询只基于查询冗余表,而后经过in的方式从主信息表得到内容。
优势是结构扩展很是方便,只须要扩展新的查询信息表便可,核心思路是,只有查询才须要独立的索引结构,展示无需独立字段。
缺点是只适合于相对固定的查询架构,对于更加灵活的组合查询一筹莫展。
3)基于统计的冗余结构
为了减小会涉及大规模影响结果集的表数据操做,好比count,sum操做。应将一些统计类数据经过冗余数据结构保存。
冗余数据结构可能以字段方式存在,也可能以独立数据表结构存在,可是都应能经过源数据表恢复。
实战范例:
论坛板块的发帖量,回帖量,每日新增数据等。
网站每日新增用户数等。
参见Discuz论坛系统数据结构,有较多相关结构。
参见前文分段积分结构,是典型用于统计的冗余结构。
后台能够经过源数据表更新该数字。
Redis的Zset类型能够理解为存在一种冗余统计结构。
4)历史数据表 历史数据表对应于热点数据表,将需求较少又不能丢弃的数据存入,仅在少数状况下被访问。