最好超过20的MySQL性能优化经验分享
1。优化查询缓存的查询
大多数MySQL服务器打开查询缓存,这是提高性的最有效的方法之一,这是由MySQL数据库引擎处理的。当许多相同的查询多次执行时,这些查询结果将被放入缓存中,以便同一个查询在没有操作表的情况下直接访问缓存结果。
这里的主要问题是程序员很容易忽略。因为我们的一些查询语句,MySQL不使用缓存:
复制代码代码如下所示:
查询缓存未打开
r = mysql_query(选择用户名从用户那里signup_date(CURDATE)> = );
查询缓存
今天美元=日期(当前);
r = mysql_query(选择用户名从用户那里signup_date > = $今天);
以上两个SQL语句之间的区别是CURDATE(),和MySQL的查询缓存不在此工作的功能。所以,SQL函数像现在()和兰德(或)不打开查询缓存,因为这些函数的返回是不确定的,所以你需要使用一个变量取代MySQL的函数,从而开启缓存。
2。解释您的选择查询
使用解释关键字可以让您了解MySQL如何处理SQL语句,这可以帮助您分析查询语句或表结构的性能瓶颈。
解释查询还将告诉您如何使用索引键,以及如何查找和排序数据表……等待,等待。
挑一个你的SELECT语句(推荐最复杂,多表连接),并添加关键词解释前面。你可以使用phpmyadmin来做这个。然后,你会看到一个形式。在下面的例子中,我们忘了添加group_id指数有一个表连接:
当我们group_id场指数:
正如我们所看到的,前面的结果显示,搜索了7883行,而后者只搜索两行的9行和16行,查看行列可以发现潜在的性能问题。
三.在仅使用一行数据时使用限制1
当您查询表一段时间时,您知道只有一个结果,但您可能需要转到提取游标,或者您可以检查返回的记录数。
在这种情况下,添加限制1可以提高性能。这样,MySQL数据库引擎将在查找一段数据之后停止搜索,而不是继续查看记录的数据。
下面的示例是为了找出是否有一个中国用户,很明显,后面的用户比以前的用户效率更高(注意,第一个是选择*,第二个是select 1)。
复制代码代码如下所示:
无/效率:
r = mysql_query(SELECT * FROM用户所在国=中国);
如果(mysql_num_rows(r)> 0){
…
}
有效的:
r = mysql_query(选择1从用户那里'china'limit国= 1 );
如果(mysql_num_rows(r)> 0){
…
}
4。index for search fields
索引不一定是主键或唯一字段。如果表中有一个字段,您将总是被用来进行搜索。然后,请为它建立索引。
从上面,你可以看到搜索字符串last_name像'一% ',一个是一个指标,一是没有指标,且性能差4倍左右。
另外,你也需要知道什么样的搜索是不能使用正常的指标。例如,当你需要搜索大量的文章,如一个词:哪里是苹果post_content %,指数可能是毫无意义的,你可能需要使用MySQL全文本索引或为自己造一个指标(比如搜索关键词或标签是什么)
5。在联接表中使用相当类型的示例并对其进行索引
如果应用程序有很多连接查询,那么应该确认两个表中的联接字段被索引。
此外,用于联接的字段应该是相同的类型。例如,如果要将十进制字段与int字段连接相结合,MySQL将不能使用它们的索引。对于这些字符串类型,您需要具有相同的字符集。
复制代码代码如下所示:
在国营公司找到
r = mysql_query(选择company_name用户
左连接公司(users.state =公司。状态)
在users.id = $ user_id );
两个状态字段应该被索引,但是应该是相同的字符集类型。
6000万不要用兰德()命令
要破坏返回的数据行吗随机拾取数据我不知道是谁发明了这个用法,但是很多新手喜欢使用它,但是你不知道性能问题有多严重。
如果你真的想搞乱返回的数据线,你有一个实现这一目标的方法。这只会降低你的数据库的性能指数。这里的问题是,MySQL将要执行rand()函数(以CPU时间),这是记录行每行的记录,然后对其进行排序。即使你使用极限1,也帮不上(因为你想要的那种)
下面的示例是一个随机选择的记录
复制代码代码如下所示:
不要这样做:
r = mysql_query(选择由兰德用户订单用户名()限1);
那会更好:
r = mysql_query(select count(*)从用户);
美元D = mysql_fetch_row(r);
兰德= mt_rand美元(0,$ { 0 } - 1);
r = mysql_query(选择用户限制为1兰特,用户名);
7。避免选择*
数据库中读取的数据越多,查询就越慢。如果数据库服务器和Web服务器是两个独立的服务器,这也会增加网络传输的负载。
所以,你应该养成养成你所需要的好习惯。
复制代码代码如下所示:
不建议
r = mysql_query(选择*从用户那里user_id = 1 );
美元D = mysql_fetch_assoc(r);
回声欢迎{ $ { 'username} };
建议
r = mysql_query(选择用户名从用户那里user_id = 1 );
美元D = mysql_fetch_assoc(r);
回声欢迎{ $ { 'username} };
8。总是为每个表设置一个ID
我们应该建立一个ID为每个数据库中的表的主键,而且最好的是一个int型(推荐使用无符号),并成立了一个auto_increment标志自动添加。
即使你的用户表有一个字段和一个主密钥称为电子邮件,你不让它的主键,VARCHAR类型的使用为主键会降低性能。此外,在你的程序中,你应该使用表的ID来构造你的数据结构。
此外,在MySQL数据引擎下,仍然存在一些需要使用主键的操作。在这种情况下,主键的性能和设置变得非常重要,如集群、分区等。
在这里,只有一个例外,那就是,链接表的外键,也就是说,该表的主键是由单个表的几个主要关键。我们称这个外键。例如,有一个学生的桌子,有学生证,有一个课程表的ID,所以成绩表的相关表,它涉及学生表和课程表,在成绩表、学生证和课程编号叫外键,主键一起构成。
9。而不是使用varchar枚举
枚举类型是非常快速和紧凑的。事实上,它是保存的字段,但其外观显示为一个字符串,它变得相当完美的使用这个字段来做一些选项列表。
如果你有一个领域,如性别、国家、民族、国家或部门,你知道这些字段的值是有限的,固定的,所以你应该使用ENUM而不是VARCHAR。
MySQL也有一个建议(见第十)告诉你如何重新组织你的表结构。当你有一个VARCHAR字段时,这个建议会告诉你把它改变为枚举类型与过程分析()你可以得到一些建议。
10。从过程分析中获得建议()
过程分析()将让MySQL帮助您分析您的字段及其实际数据,并会给您一些有用的建议。
例如,如果你创建一个int主键字段,但没有太多的数据,然后分析()会建议你改变该字段的类型为MEDIUMINT。或者你使用varchar字段,因为没有太多的数据,你可能会得到一个建议,你可以改变它枚举。这些建议可能是因为数据是不够的,所以决策不够准确。
在后台,你可以通过点击了表结构看表时查看这些建议
请务必注意,这些建议只有在你的表单中有越来越多的数据时才成为准确的。
11。尽可能不要使用null。
除非您有一个非常特殊的理由来使用null值,否则您应该始终保持字段不为空,这似乎有点争议。请往下看。
首先,问一下你的空与空(如果它是int,0和null)有什么区别如果你认为它们之间没有区别,那么你就不用null,你知道吗在Oracle中,空字符串和空字符串是相同的!)
不要认为null不需要空格,它需要额外的空间,当你比较时,你的程序会更复杂。当然,这并不是说你不能使用null,现实是非常复杂的,但在某些情况下,你需要使用null值。
以下是mysql自己的文档:
空列需要行中的额外空间来记录是否记录,它也被称为。
12。准备好的语句
准备语句非常类似于存储过程。它是在后台运行的SQL语句集合。我们可以通过使用准备好的语句获得很多好处,不管是性能还是安全性。
编写的语句可以检查一些绑定变量,这样可以保护程序不受sql注入攻击的影响,当然,也可以手动检查变量,但是手工检查容易出错,程序员常常忘记,当我们使用某个框架或ORM时,问题会更好。
在性能方面,当相同的查询被多次使用时,它将给您带来相当的性能优势。
虽然MySQL的最新版本在准备语句的传输中使用二进制的情况,这使得网络传输非常高效。
当然,有些情况下我们需要避免使用准备好的语句,因为它不支持查询缓存,但据说版本5.1得到了支持。
在PHP中使用准备好的语句,你可以看看它的使用手册:mysqli扩展或使用数据库抽象层,如PDO。
复制代码代码如下所示:
创建准备好的语句
如果(美元支撑=美元mysqli ->准备(选择用户名,用户状态=)){
绑定参数
支撑美元-> bind_param(
实现
支撑美元->执行();
绑定的结果
支撑美元-> bind_result($用户名);
移动游标
支撑美元->取();
printf(%s为%s
支撑美元->关闭();
}
13。无缓冲的查询
在正常情况下,当您在脚本中执行SQL语句时,程序将停止,直到SQL语句返回,然后程序继续下去。
在这种情况下,有在PHP文件的一个很好的解释:这mysql_unbuffered_query()函数:
mysql_unbuffered_query(发送)的SQL查询查询mysql没有自动取缓冲结果行为mysql_query(一样)这节省了大量的内存与SQL查询,产生大的结果集,你可以开始工作的结果集的第一行后立即被检索你不用等直到完整的SQL查询进行了。
上述句子的翻译是mysql_unbuffered_query()发送一个SQL语句MySQL而不是mysql_query()自动fethch和缓存的结果。这将节省相当大的内存,尤其是那些会产生很多结果。你不需要等到所有的结果都回来。您只需要返回第一行数据,您就可以立即开始查询结果。
然而,会有一些限制。因为你读了所有的线,或者你想打电话给mysql_free_result()先下查询()清除的效果。同时,mysql_num_rows mysql_data_seek()或()将不会被使用。所以,如果你使用一个非缓冲的查询,你需要仔细考虑它。
14。将IP地址保存为无符号整数。
很多程序员都会创建一个VARCHAR(15)字段来代替塑料IP字符串形式存储。如果你用塑料来保存它,只需要4个字节,你可以有一个固定长度的字段。此外,这将使你的查询的优势,尤其是当你需要使用这样的一个情况:IP IP1和IP2之间。
我们需要使用无符号int,因为IP地址将使用整个32位无符号的塑料。
为您的查询,您可以使用inet_aton()将一个字符串IP为形式,并使用inet_ntoa()将塑造成一个字符串IP。在PHP,也有这样的功能,ip2long()和long2ip()。
1 $ R =更新用户设置IP = inet_aton({ } { } _server美元'remote_addr ' '),user_id = $ user_id ;
15。定长表会更快。
如果表中的所有字段都是固定长度,整个表格将被视为静态或fixed-length.for例子,没有下面的表中的字段类型:文本,VARCHAR,BLOB。只要你有一个这样的领域,这表不是一个固定长度的静态表,所以MySQL引擎会以另一种方式处理。
固定长度表提高了性能,因为MySQL搜索速度更快,因为这些固定长度很容易计算下一个数据的偏移量,所以自然阅读也会很快发生。如果字段不长,那么,每隔一秒钟查找下一个,你需要程序找到主关键字。
另外,固定长度的表更容易被缓存和重建,但是唯一的副作用是固定长度的字段会浪费一些空间,因为固定长度的字段是分配了很大的空间,不管您使用与否。
使用垂直分割技术(见下一个),你可以把你的表分成两个,一个是固定的,一个是不长的。
16。垂直分割
垂直分割是一种将数据库中的表转换为列的方法。它可以减少复杂度和字段数,从而达到优化的目的。(在一个银行项目之前,我看到一个有100多个字段的表,非常可怕)。
示例1:用户表中有一个字段,它是家庭地址。此字段为可选字段。当你操作数据库时,除了个人信息外,你不需要阅读或重写这个字段。那么你为什么不把它放在另一个表中呢这会使你的桌子表现更好。如果您考虑一下,在大量的时间内,对于用户表,只会使用用户ID、用户名、密码、用户角色等,较小的表总是有很好的性能。
例二:你有一个名为last_login,将每一次更新用户登录。然而,每一个更新的原因表的查询缓存是空的。所以你可以把这一领域的另一个表中,这样你就不会影响你的用户ID、用户名和用户角色,因为查询缓存可以帮助你提高性能。
此外,您需要注意的是,这些字段形成的表不会定期地连接,否则它们将比未分区的更差。
17。分离大的删除或插入语句
如果你需要在一个在线网站上执行一个大的删除或插入查询,你必须非常小心避免你的操作和停止你的整个网站。因为这两个操作将锁定表,表被锁定,其他操作不来了。
Apache有很多的子进程或线程,它很有效,我们的服务器不需要太多的子进程,线程和数据库链接。这是服务器资源的一个巨大资源,尤其是内存。
如果你把你的表锁一段时间,比如30秒,那么到一个非常高的流量站点30秒,累积访问过程线程,数据库链接,打开文件的数量,不仅会让你的Web服务崩溃,也会使你的整个服务器立即挂断。
所以,如果你有一个大问题,你要确定它是分裂的,使用极限条件是一个很好的方法:
复制代码代码如下所示:
当(1){
只做 1000
mysql_query(删除日志log_date '2009-11-01'limit < = 1000);
(如果)(mysql_affected_rows = = 0){
不能删除,退出!
打破;
}
每一次休息一会儿
Usleep(50000);
}
18个越小,就越快。
对于大多数数据库引擎来说,硬盘操作可能是最重要的瓶颈,因此,将数据压缩起来是非常有帮助的,因为它减少了对硬盘的访问。
查看MySQL文档存储需求以查看所有数据类型。
如果表中只有几个列(例如,字典表和配置表),那么我们就没有理由使用int来做主键。使用MEDIUMINT,SMALLINT或更小的TINYINT会更经济。如果你不需要记录时间,最好使用datetime日期比。
当然,你还需要留有足够的扩展空间,足够你去做这件事情,你会死的很难看,看到Slashdot的例子(2009年11月06),一个简单的ALTER TABLE语句花了3个多小时,因为有一千六百万个数据。
19。选择正确的存储引擎
有两个MySQL存储引擎MyISAM和InnoDB引擎,各有利弊。前凉壳第MySQL InnoDB和MyISAM:讨论这件事。
MyISAM是适合于一些需要大量查询的应用,但它并不适合大量很好的写操作,即使你只需要一个更新的领域,整个表都会被锁起来,和其他进程,甚至阅读的过程,不能经营到读操作完成。此外,MyISAM是超级快,select count(*)。
InnoDB的趋势将是一个非常复杂的存储引擎,对于一些小的应用会比MyISAM慢。他是支持行锁,所以当写操作是更多,那就更好了。而且他还支持更高级的应用,如业务。
这是mysql手册
*目标= _blankmyisam存储引擎
* InnoDB存储引擎
20。使用对象关系映射器(对象关系映射器)
使用ORM(对象关系映射器),您可以获得可靠的性能提升。ORM可以做的所有事情也可以手工编写,但需要高级专家。
ORM最重要的一点是延迟加载,也就是说,只有在需要获取值时才可以这样做,但同时也要注意这个机制的副作用,因为它可能会降低性能,因为它会创建许多小的和许多小的查询。
ORM还可以将SQL语句打包到事务中,这比单独执行它们要快得多。
目前,个人喜爱的PHP的ORM是:原理。
21。细心的永久链接
永久链接的目的是为了减少次MySQL链接数是重新创建。当一个链接被创建,它始终处于连接状态,即使数据库操作结束。此外,由于我们的Apache开始重用它的子进程,也就是说,下一个HTTP请求将重用Apache的子进程和重用相同的MySQL链接。
* PHP手册:mysql_pconnect()
从理论上讲,这听起来很好,但从个人经验(以及大多数人)来看,这个函数会带来更多麻烦,因为只有有限数量的链接、内存问题、文件句柄数等等。
此外,Apache在一个非常并行的环境中运行,创建了许多进程。这就是为什么这个永久链接的机制不能正常工作的原因。在决定使用一个永久链接之前,您需要考虑整个系统的体系结构。
文章:源