MySQL性能优化必备25条.docx

上传人:b****5 文档编号:6187177 上传时间:2023-01-04 格式:DOCX 页数:17 大小:89.99KB
下载 相关 举报
MySQL性能优化必备25条.docx_第1页
第1页 / 共17页
MySQL性能优化必备25条.docx_第2页
第2页 / 共17页
MySQL性能优化必备25条.docx_第3页
第3页 / 共17页
MySQL性能优化必备25条.docx_第4页
第4页 / 共17页
MySQL性能优化必备25条.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

MySQL性能优化必备25条.docx

《MySQL性能优化必备25条.docx》由会员分享,可在线阅读,更多相关《MySQL性能优化必备25条.docx(17页珍藏版)》请在冰豆网上搜索。

MySQL性能优化必备25条.docx

MySQL性能优化必备25条

今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显。

关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情。

当我们去设计数据库表结构,对操作数据库时(尤其是查表时的SQL语句),我们都需要注意数据操作的性能。

这里,我们不会讲过多的SQL语句的优化,而只是针对MySQL这一Web应用最多的数据库。

希望下面的这些优化技巧对你有用。

1.为查询缓存优化你的查询2

2.EXPLAIN你的SELECT查询2

3.当只要一行数据时使用LIMIT13

4.存储引擎优化3

5.在Join表的时候使用相当类型的例,并将其索引6

6.千万不要ORDERBYRAND()6

7.避免SELECT*6

8.永远为每张表设置一个ID7

9.使用ENUM而不是VARCHAR7

10.从PROCEDUREANALYSE()取得建议7

11.尽可能的使用NOTNULL8

12.PreparedStatements8

13.无缓冲的查询9

14.把IP地址存成UNSIGNEDINT9

15.固定长度的表会更快9

16.垂直分割9

17.拆分大的DELETE或INSERT语句10

18.越小的列会越快10

19.选择正确的存储引擎10

20.使用一个对象关系映射器(ObjectRelationalMapper)11

21.小心“永久链接”11

22、分库分表11

23、不停机修改mysql表结构11

24、MySQL性能优化的参数12

25.为搜索字段建索引13

1.为查询缓存优化你的查询

大多数的MySQL服务器都开启了查询缓存。

这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。

当有很多相同的查询被执行了多次的时候,这些查询结果会被放到一个缓存中,这样,后续的相同的查询就不用操作表而直接访问缓存结果了。

这里最主要的问题是,对于程序员来说,这个事情是很容易被忽略的。

因为,我们某些查询语句会让MySQL不使用缓存。

请看下面的示例:

//查询缓存不开启

$r=mysql_query("SELECTusernameFROMuserWHEREsignup_date>=CURDATE()");

//开启查询缓存

$today=date("Y-m-d");

$r=mysql_query("SELECTusernameFROMuserWHEREsignup_date>='$today'");

上面两条SQL语句的差别就是CURDATE(),MySQL的查询缓存对这个函数不起作用。

所以,像NOW()和RAND()或是其它的诸如此类的SQL函数都不会开启查询缓存,因为这些函数的返回是会不定的易变的。

所以,你所需要的就是用一个变量来代替MySQL的函数,从而开启缓存。

2.EXPLAIN你的SELECT查询

使用 EXPLAIN 关键字可以让你知道MySQL是如何处理你的SQL语句的。

这可以帮你分析你的查询语句或是表结构的性能瓶颈。

EXPLAIN的查询结果还会告诉你,你的索引主键被如何利用的,你的数据表是如何被搜索和排序的……等等。

挑一个你的SELECT语句(推荐挑选那个最复杂的,有多表联接的),把关键字EXPLAIN加到前面。

你可以使用phpmyadmin来做这个事。

然后,你会看到一张表格。

下面的这个示例中,我们忘记加上了group_id索引,并且有表联接:

当我们为group_id字段加上索引后:

我们可以看到,前一个结果显示搜索了7883行,而后一个只是搜索了两个表的9和16行。

查看rows列可以让我们找到潜在的性能问题。

3.当只要一行数据时使用LIMIT1

当你查询表的有些时候,你已经知道结果只会有一条结果,但因为你可能需要去fetch游标,或是你也许会去检查返回的记录数。

在这种情况下,加上LIMIT1可以增加性能。

这样一样,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据。

下面的示例,只是为了找一下是否有“中国”的用户,很明显,后面的会比前面的更有效率。

(请注意,第一条中是Select*,第二条是Select1)

//没有效率的:

$r=mysql_query("SELECT*FROMuserWHEREcountry='China'");

if(mysql_num_rows($r)>0){

//...

}

//有效率的:

$r=mysql_query("SELECT1FROMuserWHEREcountry='China'LIMIT1");

if(mysql_num_rows($r)>0){

//...

}

4.存储引擎优化

  MySQL支持不同的存储引擎,主要使用的有MyISAM和InnoDB。

  4.1MyISAM

  MyISAM管理非事务表。

它提供高速存储和检索,以及全文搜索能力。

MyISAM在所有MySQL配置里被支持,它是默认的存储引擎,除非配置MySQL默认使用另外一个引擎。

  4.1.1MyISAM特性

  4.1.1.1MyISAMProperties

  1)不支持事务,宕机会破坏表

  2)使用较小的内存和磁盘空间

  3)基于表的锁,并发更新数据会出现严重性能问题

  4)MySQL只缓存Index,数据由OS缓存

  4.1.1.2TypicalMyISAMusages

  1)日志系统

  2)只读或者绝大部分是读操作的应用

  3)全表扫描

  4)批量导入数据

  5)没有事务的低并发读/写

  4.1.2MyISAM优化要点

  1)声明列为NOTNULL,可以减少磁盘存储。

  2)使用optimizetable做碎片整理,回收空闲空间。

注意仅仅在非常大的数据变化后运行。

  3)Deleting/updating/adding大量数据的时候禁止使用index。

使用ALTERTABLEtDISABLEKEYS。

  4)设置myisam_max_[extra]_sort_file_size足够大,可以显著提高repairtable的速度。

  4.1.3MyISAMTableLocks

  1)避免并发insert,update。

  2)可以使用insertdelayed,但是有可能丢失数据。

  3)优化查询语句。

  4)水平分区。

  5)垂直分区。

  6)如果都不起作用,使用InnoDB。

  4.1.4MyISAMKeyCache

  1)设置key_buffer_sizevariable。

MyISAN最主要的cache设置,用于缓存MyISAM表格的index数据,该参数只对MyISAM有影响。

通常在只使用MyISAM的Server中设置25-33%的内存大小。

  2)可以使用几个不同的KeyCaches(对一些hotdata)。

  a)SETGLOBALtest.key_buffer_size=512*1024;

  b)CACHEINDEXt1.i1,t2.i1,t3INtest;

  2)Preloadindex到Cache中可以提高查询速度。

因为preloadingindex是顺序的,所以非常快。

  a)LOADINDEXINTOCACHEt1,t2IGNORELEAVES;

  4.2InnoDB

  InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。

InnoDB提供rowlevellock,并且也在SELECT语句提供一个Oracle风格一致的非锁定读。

这些特色增加了多用户部署和性能。

没有在InnoDB中扩大锁定的需要,因为在InnoDB中rowlevellock适合非常小的空间。

InnoDB也支持FOREIGNKEY约束。

在SQL查询中,你可以自由地将InnoDB类型的表与其它MySQL的表的类型混合起来,甚至在同一个查询中也可以混合。

  InnoDB是为在处理巨大数据量时获得最大性能而设计的。

它的CPU使用效率非常高。

  InnoDB存储引擎已经完全与MySQL服务器整合,InnoDB存储引擎为在内存中缓存数据和索引而维持它自己的缓冲池。

InnoDB存储它的表&索引在一个表空间中,表空间可以包含数个文件(或原始磁盘分区)。

这与MyISAM表不同,比如在MyISAM表中每个表被存在分离的文件中。

InnoDB表可以是任何大小,即使在文件尺寸被限制为2GB的操作系统上。

  许多需要高性能的大型数据库站点上使用了InnoDB引擎。

著名的Internet新闻站点Slashdot.org运行在InnoDB上。

Mytrix,Inc.在InnoDB上存储超过1TB的数据,还有一些其它站点在InnoDB上处理平均每秒800次插入/更新的负荷。

  4.2.1InnoDB特性

  4.2.1.1InnoDBProperties

  1)支持事务,ACID,外键。

  2)Rowlevellocks。

  3)支持不同的隔离级别。

  4)和MyISAM相比需要较多的内存和磁盘空间。

  5)没有键压缩。

  6)数据和索引都缓存在内存hash表中。

  4.2.1.2InnoDBGoodFor

  1)需要事务的应用。

  2)高并发的应用。

  3)自动恢复。

  4)较快速的基于主键的操作。

  4.2.2InnoDB优化要点

  1)尽量使用short,integer的主键。

  2)Load/Insert数据时按主键顺序。

如果数据没有按主键排序,先排序然后再进行数据库操作。

  3)在Load数据是为设置SETUNIQUE_CHECKS=0,SETFOREIGN_KEY_CHECKS=0,可以避免外键和唯一性约束检查的开销。

  4)使用prefixkeys。

因为InnoDB没有key压缩功能。

  4.2.3InnoDB服务器端设定

  innodb_buffer_pool_size:

这是InnoDB最重要的设置,对InnoDB性能有决定性的影响。

默认的设置只有8M,所以默认的数据库设置下面InnoDB性能很差。

在只有InnoDB存储引擎的数据库服务器上面,可以设置60-80%的内存。

更精确一点,在内存容量允许的情况下面设置比InnoDBtablespaces大10%的内存大小。

  innodb_data_file_path:

指定表数据和索引存储的空间,可以是一个或者多个文件。

最后一个数据文件必须是自动扩充的,也只有最后一个文件允许自动扩充。

这样,当空间用完后,自动扩充数据文件就会自动增长(以8MB为单位)以容纳额外的数据。

例如:

innodb_data_file_path=/disk1/ibdata1:

900M;/disk2/ibdata2:

50M:

autoextend两个数据文件放在不同的磁盘上。

数据首先放在ibdata1中,当达到900M以后,数据就放在ibdata2中。

一旦达到50MB,ibdata2将以8MB为单位自动增长。

如果磁盘满了,需要在另外的磁盘上面增加一个数据文件。

  innodb_autoextend_increment:

默认是8M,如果一次insert数据量比较多的话,可以适当增加.

  innodb_data_home_dir:

放置表空间数据的目录,默认在mysql的数据目录,设置到和MySQL安装文件不同的分区可以提高性能。

  innodb_log_file_size:

该参数决定了recoveryspeed。

太大的话recovery就会比较慢,太小了影响查询性能,一般取256M可以兼顾性能和recovery的速度。

  innodb_log_buffer_size:

磁盘速度是很慢的,直接将log写道磁盘会影响InnoDB的性能,该参数设定了logbuffer的大小,一般4M。

如果有大的blob操作,可以适当增大。

  innodb_flush_logs_at_trx_commit=2:

该参数设定了事务提交时内存中log信息的处理。

  1)=1时,在每个事务提交时,日志缓冲被写到日志文件,对日志文件做到磁盘操作的刷新。

TrulyACID。

速度慢。

  2)=2时,在每个事务提交时,日志缓冲被写到文件,但不对日志文件做到磁盘操作的刷新。

只有操作系统崩溃或掉电才会删除最后一秒的事务,不然不会丢失事务。

  3)=0时,日志缓冲每秒一次地被写到日志文件,并且对日志文件做到磁盘操作的刷新。

任何mysqld进程的崩溃会删除崩溃前最后一秒的事务

  innodb_file_per_table:

可以存储每个InnoDB表和它的索引在它自己的文件中。

  transaction-isolation=READ-COMITTED:

如果应用程序可以运行在READ-COMMITED隔离级别,做此设定会有一定的性能提升。

  innodb_flush_method:

设置InnoDB同步IO的方式:

  1)Default–使用fsync()。

  2)O_SYNC以sync模式打开文件,通常比较慢。

  3)O_DIRECT,在Linux上使用DirectIO。

可以显著提高速度,特别是在RAID系统上。

避免额外的数据复制和doublebuffering(mysqlbuffering和OSbuffering)。

  innodb_thread_concurrency:

InnoDBkernel最大的线程数。

  1)最少设置为(num_disks+num_cpus)*2。

2)可以通过设置成1000来禁止这个限制

5.在Join表的时候使用相当类型的例,并将其索引

如果你的应用程序有很多JOIN查询,你应该确认两个表中Join的字段是被建过索引的。

这样,MySQL内部会启动为你优化Join的SQL语句的机制。

而且,这些被用来Join的字段,应该是相同的类型的。

例如:

如果你要把DECIMAL字段和一个INT字段Join在一起,MySQL就无法使用它们的索引。

对于那些STRING类型,还需要有相同的字符集才行。

(两个表的字符集有可能不一样)

//在state中查找company

$r=mysql_query("SELECTcompany_nameFROMusers

LEFTJOINcompaniesON(users.state=companies.state)

WHEREusers.id=$user_id");

//两个state字段应该是被建过索引的,而且应该是相当的类型,相同的字符集。

6.千万不要ORDERBYRAND()

想打乱返回的数据行?

随机挑一个数据?

真不知道谁发明了这种用法,但很多新手很喜欢这样用。

但你却不了解这样做有多么可怕的性能问题。

如果你真的想把返回的数据行打乱了,你有N种方法可以达到这个目的。

这样使用只让你的数据库的性能呈指数级的下降。

这里的问题是:

MySQL会不得不去执行RAND()函数(很耗CPU时间),而且这是为了每一行记录去记行,然后再对其排序。

就算是你用了Limit1也无济于事(因为要排序)

下面的示例是随机挑一条记录

//千万不要这样做:

$r=mysql_query("SELECTusernameFROMuserORDERBYRAND()LIMIT1");

//这要会更好:

$r=mysql_query("SELECTcount(*)FROMuser");

$d=mysql_fetch_row($r);

$rand=mt_rand(0,$d[0]-1);

$r=mysql_query("SELECTusernameFROMuserLIMIT$rand,1");

7.避免SELECT*

从数据库里读出越多的数据,那么查询就会变得越慢。

并且,如果你的数据库服务器和WEB服务器是两台独立的服务器的话,这还会增加网络传输的负载。

所以,你应该养成一个需要什么就取什么的好的习惯。

//不推荐

$r=mysql_query("SELECT*FROMuserWHEREuser_id=1");

$d=mysql_fetch_assoc($r);

echo"Welcome{$d['username']}";

//推荐

$r=mysql_query("SELECTusernameFROMuserWHEREuser_id=1");

$d=mysql_fetch_assoc($r);

echo"Welcome{$d['username']}";

8.永远为每张表设置一个ID

我们应该为数据库里的每张表都设置一个ID做为其主键,而且最好的是一个INT型的(推荐使用UNSIGNED),并设置上自动增加的AUTO_INCREMENT标志。

就算是你users表有一个主键叫“email”的字段,你也别让它成为主键。

使用VARCHAR类型来当主键会使用得性能下降。

另外,在你的程序中,你应该使用表的ID来构造你的数据结构。

而且,在MySQL数据引擎下,还有一些操作需要使用主键,在这些情况下,主键的性能和设置变得非常重要,比如,集群,分区……

在这里,只有一个情况是例外,那就是“关联表”的“外键”,也就是说,这个表的主键,通过若干个别的表的主键构成。

我们把这个情况叫做“外键”。

比如:

有一个“学生表”有学生的ID,有一个“课程表”有课程ID,那么,“成绩表”就是“关联表”了,其关联了学生表和课程表,在成绩表中,学生ID和课程ID叫“外键”其共同组成主键。

9.使用ENUM而不是VARCHAR

ENUM 类型是非常快和紧凑的。

实际上,其保存的是TINYINT,但其外表上显示为字符串。

这样一来,用这个字段来做一些选项列表变得相当的完美。

如果你有一个字段,比如“性别”,“国家”,“民族”,“状态”或“部门”,你知道这些字段的取值是有限而且固定的,那么,你应该使用ENUM而不是VARCHAR。

MySQL也有一个“建议”(见第十条)告诉你怎么去重新组织你的表结构。

当你有一个VARCHAR字段时,这个建议会告诉你把其改成ENUM类型。

使用PROCEDUREANALYSE()你可以得到相关的建议。

10.从PROCEDUREANALYSE()取得建议

PROCEDUREANALYSE() 会让MySQL帮你去分析你的字段和其实际的数据,并会给你一些有用的建议。

只有表中有实际的数据,这些建议才会变得有用,因为要做一些大的决定是需要有数据作为基础的。

例如,如果你创建了一个INT字段作为你的主键,然而并没有太多的数据,那么,PROCEDUREANALYSE()会建议你把这个字段的类型改成MEDIUMINT。

或是你使用了一个VARCHAR字段,因为数据不多,你可能会得到一个让你把它改成ENUM的建议。

这些建议,都是可能因为数据不够多,所以决策做得就不够准。

在phpmyadmin里,你可以在查看表时,点击“Proposetablestructure”来查看这些建议

一定要注意,这些只是建议,只有当你的表里的数据越来越多时,这些建议才会变得准确。

一定要记住,你才是最终做决定的人。

11.尽可能的使用NOTNULL

除非你有一个很特别的原因去使用NULL值,你应该总是让你的字段保持NOTNULL。

这看起来好像有点争议,请往下看。

首先,问问你自己“Empty”和“NULL”有多大的区别(如果是INT,那就是0和NULL)?

如果你觉得它们之间没有什么区别,那么你就不要使用NULL。

(你知道吗?

在Oracle里,NULL和Empty的字符串是一样的!

不要以为NULL不需要空间,其需要额外的空间,并且,在你进行比较的时候,你的程序会更复杂。

当然,这里并不是说你就不能使用NULL了,现实情况是很复杂的,依然会有些情况下,你需要使用NULL值。

下面摘自MySQL自己的文档:

“NULLcolumnsrequireadditionalspaceintherowtorecordwhethertheirvaluesareNULL.ForMyISAMtables,eachNULLcolumntakesonebitextra,roundeduptothenearestbyte.”

12.PreparedStatements

PreparedStatements很像存储过程,是一种运行在后台的SQL语句集合,我们可以从使用preparedstatements获得很多好处,无论是性能问题还是安全问题。

PreparedStatements可以检查一些你绑定好的变量,这样可以保护你的程序不会受到“SQL注入式”攻击。

当然,你也可以手动地检查你的这些变量,然而,手动的检查容易出问题,而且很经常会被程序员忘了。

当我们使用一些framework或是ORM的时候,这样的问题会好一些。

在性能方面,当一个相同的查询被使用多次的时候,这会为你带来可观的性能优势。

你可以给这些PreparedStatements定义一些参数,而MySQL只会解析一次。

虽然最新版本的MySQL在传输PreparedStatements是使用二进制形势,所以这会使得网络传输非常有效率。

当然,也有一些情况下,我们需要避免使用PreparedStatements,因为其不支持查询缓存。

但据说版本5.1后支持了。

在PHP中要使用preparedstatements,你可以查看其使用手册:

mysqli扩展 或是使用数据库抽象层,如:

 PDO.

//创建preparedstatement

if($stmt=$mysqli->prepare("SELECTusernameFROMuserWHEREstate=?

")){

//绑定参数

$stmt->bind_param("s",$state);

//执行

$stmt->execute();

//绑定结果

$stmt->bind_result($username);

//移动游标

$stmt->fetch();

printf("%sisfrom%s\n",$username,$state);

$stmt->close();

}

13.无缓冲的查询

正常的情况下,当你在当你在你的脚本中执行一个SQL语句的时候,你的程序会停在那里直到没这个SQL语句返回,然后你的程序再往下继续执行。

你可以使用无缓冲查询来改变这个行为。

关于这个事情,在PHP的文档中有一个非常

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1