① 优化MySQL所在服务器内核(此优化通常由运维人员完成)。mysql
② 对MySQL配置参数进行优化(my.cnf)此优化须要进行压力测试来进行参数调整。程序员
③ 对SQL语句以及表优化。sql
1:MySQL 默认的最大链接数为 100,能够在 mysql 客户端使用如下命令查看
mysql> show variables like 'max_connections';
2:查看当前访问Mysql的线程
mysql> show processlist;
3:设置最大链接数
mysql>set globle max_connections = 5000;
最大可设置16384,超过没用
4:查看当前被使用的connections
mysql>show globle status like 'max_user_connections'数据库
① 为查询缓存优化查询缓存
② EXPLAIN 咱们的SELECT查询(能够查看执行的行数)安全
③ 当只要一行数据时使用LIMIT 1性能优化
④ 为搜索字段创建索引服务器
⑤ 在Join表的时候使用至关类型的列,并将其索引网络
⑥ 千万不要 ORDER BY RAND ()数据结构
⑦ 避免SELECT *
⑧ 永远为每张表设置一个ID
⑨ 可使用ENUM 而不要VARCHAR
⑩ 尽量的使用NOT NULL
⑪ 固定长度的表会更快
⑫ 垂直分割
⑬ 拆分打的DELETE或INSERT语句
⑭ 越小的列会越快
⑮ 选择正确的存储引擎
⑯ 当心 "永久连接"
具体描述以下:
(一) 使用查询缓存优化查询
大多数的MySQL服务器都开启了查询缓存。这是提升性能最有效的方法之一,并且这是被MySQL引擎处理的。当有不少相同的查询被执行了屡次的时候,这些查询结果会被放入一个缓存中,这样后续的相同查询就不用操做而直接访问缓存结果了。
这里最主要的问题是,对于咱们程序员来讲,这个事情是很容易被忽略的。由于咱们某些查询语句会让MySQL不使用缓存,示例以下:
1:SELECT username FROM user WHERE signup_date >= CURDATE()
2:SELECT username FROM user WHERE signup_date >= '2014-06-24‘
上面两条SQL语句的差异就是 CURDATE() ,MySQL的查询缓存对这个函数不起做用。因此,像 NOW() 和 RAND() 或是其它的诸如此类的SQL函数都不会开启查询缓存,由于这些函数的返回是会不定的易变的。因此,你所须要的就是用一个变量来代替MySQL的函数,从而开启缓存。
(二) 使用EXPLAIN关键字检测查询
使用EXPLAIN关键字可使咱们知道MySQL是如何处理SQL语句的,这样能够帮助咱们分析咱们的查询语句或是表结构的性能瓶颈;EXPLAIN的查询结果还会告诉咱们索引主键是如何被利用的,数据表是如何被被搜索或排序的....等等。语法格式是:EXPLAIN +SELECT语句;
咱们能够看到,前一个结果显示搜索了 7883 行,然后一个只是搜索了两个表的 9 和 16 行。查看rows列可让咱们找到潜在的性能问题。
(三)当只要一行数据时使用LIMIT 1
加上LIMIT 1能够增长性能。MySQL数据库引擎会在查找到一条数据后中止搜索,而不是继续日后查询下一条符合条件的数据记录。
(四)为搜索字段创建索引
索引不必定就是给主键或者是惟一的字段,若是在表中,有某个字段常常用来作搜索,须要将其创建索引。
索引的有关操做以下:
1.建立索引
在执行CREATE TABLE语句时能够建立索引,也能够单独用CREATE INDEX或ALTER TABLE来为表增长索引。
1.1> ALTER TABLE
ALTER TABLE 用来建立普通索引、惟一索引、主键索引和全文索引
ALTER TABLE table_name ADD INDEX index_name (column_list);
ALTER TABLE table_name ADD UNIQUE (column_list);
ALTER TABLE table_name ADD PRIMARY KEY (column_list);
ALTER TABLE table_name ADD FULLTEXT (column_list);
其中table_name是要增长索引名的表名,column_list指出对哪些列列进行索引,多列时各列之间使用半角逗号隔开。索引名index_name是可选的,若是不指定索引名称,MySQL将根据第一个索引列自动指定索引名称,另外,ALTER TABLE容许在单个语句中更改多个表,所以能够在同时建立多个索引。
1.2> CREATE INDEX
CREATE INDEX可对表增长普通索引或UNIQUE索引以及全文索引,可是不能够对表增长主键索引
CREATE INDEX index_name ON table_name (column_list);
CREATE UNIQUE index_name ON table_name (column_list);
CREATE FULLTEXT index_name ON table_name (column_list);
table_name、index_name和column_list具备与ALTER TABLE语句中相同的含义,索引名必须指定。另外,不能用CREATE INDEX语句建立PRIMARY KEY索引。
2.索引类型
普通索引INDEX:适用于name、email等通常属性
惟一索引UNIQUE:与普通索引相似,不一样的是惟一索引要求索引字段值在表中是惟一的,这一点和主键索引相似,可是不一样的是,惟一索引容许有空值。惟一索引通常适用于身份证号码、用户帐号等不容许有重复的属性字段上。
主键索引:其实就是主键,通常在建表时就指定了,不须要额外添加。
全文检索:只适用于VARCHAR和Text类型的字段。
注意:全文索引和普通索引是有很大区别的,若是创建的是普通索引,通常会使用like进行模糊查询,只会对查询内容前一部分有效,即只对前面不使用通配符的查询有效,若是先后都有通配符,普通索引将不会起做用。对于全文索引而言在查询时有本身独特的匹配方式,例如咱们在对一篇文章的标题和内容进行全文索引时:
ALTER TABLE article ADD FULLTEXT ('title', 'content'); 在进行检索时就须要使用以下的语法进行检索:
SELECT * FROM article WHERE MATCH('title', 'content') AGAINST ('查询字符串');
在使用全文检索时的注意事项:
MySql自带的全文索引只能用于数据库引擎为MYISAM的数据表,若是是其余数据引擎,则全文索引不会生效。此外,MySql自带的全文索引只能对英文进行全文检索,目前没法对中文进行全文检索。若是须要对包含中文在内的文本数据进行全文检索,咱们须要采用Sphinx(斯芬克斯)/Coreseek技术来处理中文。另外使用MySql自带的全文索引时,若是查询字符串的长度太短将没法获得指望的搜索结果。MySql全文索引所能找到的词默认最小长度为4个字符。另外,若是查询的字符串包含中止词,那么该中止词将会被忽略。
3.组合索引
组合索引又称多列索引,就是创建索引时指定多个字段属性。有点相似于字典目录,好比查询 'guo' 这个拼音的字时,首先查找g字母,而后在g的检索范围内查询第二个字母为u的列表,最后在u的范围内查找最后一个字母为o的字。好比组合索引(a,b,c),abc都是排好序的,在任意一段a的下面b都是排好序的,任何一段b下面c都是排好序的
组合索引的生效原则是 从前日后依次使用生效,若是中间某个索引没有使用,那么断点前面的索引部分起做用,断点后面的索引没有起做用;
形成断点的缘由:
前边的任意一个索引没有参与查询,后边的所有不生效。
前边的任意一个索引字段参与的是范围查询,后面的不会生效。
断点跟索引字字段在SQL语句中的位置先后无关,只与是否存在有关。在网上找到了很好的示例:
好比:
[sql] view plain copy
(a,b,c) 三个列上加了联合索引(是联合索引 不是在每一个列上单独加索引)而是创建了a,(a,b),(a,b,c)三个索引,另外(a,b,c)多列索引和 (a,c,b)是不同的。
具体实例能够说明:
[sql] view plain copy
注意:在查询时,MYSQL只能使用一个索引,若是创建的是多个单列的普通索引,在查询时会根据查询的索引字段,从中选择一个限制最严格的单例索引进行查询。别的索引都不会生效。
4.查看索引
mysql> show index from tblname;
mysql> show keys from tblname;
5.删除索引
删除索引的mysql格式 :DORP INDEX IndexName ON tab_name;
注意:不能使用索引的状况
对于普通索引而言 在使用like进行通配符模糊查询时,若是首尾之间都使用了通配符,索引时无效的。
假设查询内容的关键词为'abc'
SELECT * FROM tab_name WHERE index_column LIKE 'abc%'; #索引是有效的
SELECT * FROM tab_name WHERE index_column LIKE '%abc'; #索引是无效的
SELECT * FROM tab_name WHERE index_column LIKE '%cba'; #索引是有效的
SELECT * FROM tab_name WHERE index_column LIKE '%abc%'; #索引是无效的
当检索的字段内容比较大并且检索内容先后部分都不肯定的状况下,能够改成全文索引,并使用特定的检索方式。
(五)在join表的时候使用至关类型的列,并将其索引
若是在程序中有不少JOIN查询,应该保证两个表中join的字段时被创建过索引的。这样MySQL颞部会启动优化JOIN的SQL语句的机制。注意:这些被用来JOIN的字段,应该是相同类型的。例如:若是要把 DECIMAL 字段和一个 INT 字段Join在一块儿,MySQL就没法使用它们的索引。对于那些STRING类型,还须要有相同的字符集才行。(两个表的字符集有可能不同)
例如:
SELECT company_name FROM users LEFT JOIN companies ON (users.state = companies.state) WHERE users.id = “user_id”
两个 state 字段应该是被建过索引的,并且应该是至关的类型,相同的字符集。
(六)切记不要使用ORDER BY RAND()
若是你真的想把返回的数据行打乱了,你有N种方法能够达到这个目的。这样使用只让你的数据库的性能呈指数级的降低。这里的问题是:MySQL会不得不去执行RAND()函数(很耗CPU时间),并且这是为了每一行记录去记行,而后再对其排序。就算是你用了Limit 1也无济于事(由于要排序)
(七)避免使用SELECT *
从数据库里读出越多的数据,那么查询就会变得越慢。而且,若是咱们的数据库服务器和WEB服务器是两台独立的服务器的话,这还会增长网络传输的负载。 因此,咱们应该养成一个须要什么就取什么的好的习惯。
Hibernate性能方面就会差,它不用*,但它将整个表的全部字段全查出来
优势:开发速度快
(八)永远为每张表设置一个ID主键
咱们应该为数据库里的每张表都设置一个ID作为其主键,并且最好的是一个INT型的(推荐使用UNSIGNED),并设置上自动增长的 AUTO_INCREMENT标志。 就算是咱们 users 表有一个主键叫 “email”的字段,咱们也别让它成为主键。使用 VARCHAR 类型来当主键会使用得性能降低。另外,在咱们的程序中,咱们应该使用表的ID来构造咱们的数据结构。 并且,在MySQL数据引擎下,还有一些操做须要使用主键,在这些状况下,主键的性能和设置变得很是重要,好比,集群,分区…… 在这里,只有一个状况是例外,那就是“关联表”的“外键”,也就是说,这个表的主键,经过若干个别的表的主键构成。咱们把这个状况叫作“外键”。好比:有一个“学生表”有学生的ID,有一个“课程表”有课程ID,那么,“成绩表”就是“关联表”了,其关联了学生表和课程表,在成绩表中,学生ID和课程ID叫“外键”其共同组成主键。
(九)使用ENUM而不是VARCHAR
ENUM 类型是很是快和紧凑的。在实际上,其保存的是 TINYINT,但其外表上显示为字符串。这样一来,用这个字段来作一些选项列表变得至关的完美。 若是咱们有一个字段,好比“性别”,“国家”,“民族”,“状态”或“部门”,咱们知道这些字段的取值是有限并且固定的,那么,咱们应该使用 ENUM 而不是 VARCHAR。
(十)尽量的不要赋值为NULL
若是不是特殊状况,尽量的不要使用NULL。在MYSQL中对于INT类型而言,EMPTY是0,而NULL是空值。而在Oracle中 NULL和EMPTY的字符串是同样的。NULL也须要占用存储空间,而且会使咱们的程序判断时更加复杂。现实状况是很复杂的,依然会有些状况下,咱们须要使用NULL值。 下面摘自MySQL本身的文档: “NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”
(十一) 固定长度的表会更快
若是表中的全部字段都是“固定长度”的,整个表会被认为是 “static” 或 “fixed-length”。 例如,表中没有以下类型的字段: VARCHAR,TEXT,BLOB。只要咱们包括了其中一个这些字段,那么这个表就不是“固定长度静态表”了,这样,MySQL 引擎会用另外一种方法来处理。 固定长度的表会提升性能,由于MySQL搜寻得会更快一些,由于这些固定的长度是很容易计算下一个数据的偏移量的,因此读取的天然也会很快。而若是字段不是定长的,那么,每一次要找下一条的话,须要程序找到主键。 而且,固定长度的表也更容易被缓存和重建。不过,惟一的反作用是,固定长度的字段会浪费一些空间,由于定长的字段不管咱们用不用,他都是要分配那么多的空间。另外在取出值的时候要使用trim去除空格
(十二)垂直分割
“垂直分割”是一种把数据库中的表按列变成几张表的方法,这样能够下降表的复杂度和字段的数目,从而达到优化的目的。
(十三)拆分大的DELETE或INSERT
若是咱们须要在一个在线的网站上去执行一个大的 DELETE 或 INSERT 查询,咱们须要很是当心,要避免咱们的操做让咱们的整个网站中止相应。由于这两个操做是会锁表的,表一锁住了,别的操做都进不来了。Apache 会有不少的子进程或线程。因此,其工做起来至关有效率,而咱们的服务器也不但愿有太多的子进程,线程和数据库连接,这是极大的占服务器资源的事情,尤为是内存。若是咱们把咱们的表锁上一段时间,好比30秒钟,那么对于一个有很高访问量的站点来讲,这30秒所积累的访问进程/线程,数据库连接,打开的文件数,可能不只仅会让咱们的WEB服务Crash,还可能会让咱们的整台服务器立刻掛了。因此在使用时使用LIMIT 控制数量操做记录的数量。
(十四)越小的列会越快
对于大多数的数据库引擎来讲,硬盘操做多是最重大的瓶颈。因此,把咱们的数据变得紧凑会对这种状况很是有帮助,由于这减小了对硬盘的访问。 参看 MySQL 的文档 Storage Requirements 查看全部的数据类型。 若是一个表只会有几列罢了(好比说字典表,配置表),那么,咱们就没有理由使用 INT 来作主键,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 会更经济一些。若是咱们不须要记录时间,使用 DATE 要比 DATETIME 好得多。
(十五)选择正确的存储引擎
在MYSQL中有两个存储引擎MyISAM和InnoDB,每一个引擎都有利有弊。
MyISAM适合于一些须要大量查询的应用,可是对于大量写操做的支持不是很好。甚至一个update语句就会进行锁表操做,这时读取这张表的全部进程都没法进行操做直至写操做完成。另外MyISAM对于SELECT COUNT(*)这类的计算是超快无比的。InnoDB 的趋势会是一个很是复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。它支持“行锁” ,因而在写操做比较多的时候,会更优秀。而且,他还支持更多的高级应用,好比:事务。
MyISAM是MYSQL5.5版本之前默认的存储引擎,基于传统的ISAM类型,支持B-Tree,全文检索,可是不是事务安全的,并且不支持外键。不具备原子性。支持锁表。
InnoDB是事务型引擎,支持ACID事务(实现4种事务隔离机制)、回滚、崩溃恢复能力、行锁。以及提供与Oracle一致的不加锁的读取方式。InnoDB存储它的表和索引在一个表空间中,表空间能够包含多个文件。
MyISAM和InnoDB比较,以下图所示:
对于Linux版本的MYSQL 配置文件在 /etc/my.cnf中
在5.5以后默认的存储引擎是INNODB
能够单独进行修改也能够在建立表时修改:
ALTER TABLE tab_name ENGINE INNODB;
(十六)当心永久连接
“永久连接”的目的是用来减小从新建立MySQL连接的次数。当一个连接被建立了,它会永远处在链接的状态,就算是数据库操做已经结束了。并且,自从咱们的Apache开始重用它的子进程后——也就是说,下一次的HTTP请求会重用Apache的子进程,并重用相同的 MySQL 连接。 并且,Apache 运行在极端并行的环境中,会建立不少不少的了进程。这就是为何这种“永久连接”的机制工做地很差的缘由。在咱们决定要使用“永久连接”以前,咱们须要好好地考虑一下咱们的整个系统的架构。