1.优化查询的查询缓存大部分MySQL服务器都有查询缓存功能。这是提高性能的最有效的方法之一,这是由数据库引擎私下处理的。当同一个查询被多次执行,结果会直接从缓存里提取,这样速度就很快。 主要的问题是,这对程序员来说太简单了,不容易看到,我们很多人都容易忽略。我们实际上是可以组织查询缓存执行任务的。
查询缓存在第一行不执行的原因在于CURDTE()功能的使用。这适用于所有的非确定性功能,就像NOW()和RAND()等等。。。因为功能返回的结果是可变的。MySQL决定禁用查询器的查询缓存。我们所需要做的是通过添加一额外一行PHP,在查询前阻止它发生。 |
爱不爱吃鱼
| ||
其它翻译版本(1) |
3. 获取唯一行时使用LIMIT 1
有时当你查表时,你已经知道你正在查找的结果只有一行。你可能正在获取唯一记录,或者你可能只是查询是否存在满足你的WHERE子句条件的记录。
|
Tocy
| ||
其它翻译版本(1) |
4. 索引搜索字段索引不仅仅是为了主键或唯一键。如果你会在你的表中按照任何列搜索,你就都应该索引它们。 正如你所看到的,这个规则也适用于如 "last_name LIKE 'a%'"的部分字符串搜索。当从字符串的开头搜索时,MySQL就可以使用那一列的索引。 你也应该明白什么样搜索可以不使用有规律的索引。例如,当搜索一个单词时(例如,"WHERE post_content LIKE '%apple%'"),你将不会看到普通索引的好处。你最好使用 mysql 全文搜索或者构建你自己的索引解决方案。 |
Robbie_Zhu
|
5. 索引并对连接使用同样的字段类型
如果你的应用程序包含许多连接查询, 你需要确保连接的字段在两张表上都建立了索引。 这会影响MySQL如何内部优化连接操作。 此外,被连接的字段,需要使用同样类型。例如, 如果你使用一个DECIMAL字段, 连接另一张表的INT字段, MySQL将无法使用至少一个索引。 即使字符编码也需要使用相同的字符类型。
6. 不要ORDER BY RAND()起初这是一个听起来挺酷的技巧, 让许多菜鸟程序员陷入了这个陷阱。但你可能不知道,一旦你开始在查询中使用它,你创建了非常可怕的查询瓶颈。 如果你真的需要对结果随机排序, 这有一个更好的方法。补充一些额外代码,你将可以防止当数据成指数级增长时造成的瓶颈。关键问题是,MySQL必须在排序之前对表中的每一行执行RAND()操作(这需要处理能力),并且仅仅给出一行。
所以挑选一个小于结果数的随机数,并将其用作LIMIT子句中的偏移量。 |
snake_007
|
7. 避免使用SELECT *
从数据表中读取的数据越多,查询操作速度就越慢。它增加了磁盘操作所需的时间。此外,当数据库服务器与Web服务器分开时,由于必须在服务器之间传输数据,将会有更长的网络延迟。
8. 几乎总是有一个id字段在每个以id列为PRIMARY KEY的数据表中,优先选择AUTO_INCREMENT或者INT。 也可以优选使用UNSIGNED,因为该值不能为负的。 即使你拥有一个具有唯一用户名字段的用户表,也不要将其作为主键。 VARCHAR字段作为主键(检索)速度较慢。通过内部ID引用所有的用户数据,你的代码中将更加结构化。 有些后台操作是由MySQL引擎本身完成的,它在内部使用主键字段。当数据库设置越复杂(集群,分区等...),这就变得更加重要了。 |
Tocy
|
9. 相比VARCHAR优先使用ENUMENUM枚举类型是非常快速和紧凑的。在内部它们像TINYINT一样存储,但它们可以包含和显示字符串值。这使他们成为某些领域的完美候选。 如果有一个字段只包含几种不同的值,请使用ENUM而不是VARCHAR。例如,它可以是名为“status”的列,并且只包含诸如“active”,“inactive”,“pending”,“expired”等的值... |
Tocy
|
10. 使用PROCEDURE ANALYSE()获取建议
PROCEDURE ANALYSE() 将使用MySQL分析列结构和表中的实际数据,为你提供一些建议。它只有在数据表中有实际数据时才有用,因为这在分析决策时很重要。 例如,如果你创建了一个INT类型的主键,但没有太多行,MySQL则可能建议您改用MEDIUMINT。或者如果你使用VARCHAR字段,如果表里只有很少的取值,你可能会得到一个建议是将其转换为ENUM。 你也可以在其中一个表视图中单击phpmyadmin中的“建议表结构”链接来执行此操作。 请记住,这些只是建议。 如果你的数据表变得越来越大,他们甚至可能不是正确的建议。至于如何修改最终是你来决定。 |
Tocy
|
11. 如果可以的话使用NOT NULL
除非你有非常重要的理由使用NULL值,否则你应该设置你的列为NOT NULL。 首先,问一下你自己在空字符串值和NULL值之间(对应INT字段:0 vs. NULL)是否有任何的不同.如果没有理由一起使用这两个,那么你就不需要一个NULL字段(你知道在Oracle中NULL和空字符串是一样的吗?)。 NULL列需要额外的空间,他们增加了你的比较语句的复杂度。如果可以的话尽量避免它们。当然,我理解一些人,他们也许有非常重要的理由使用NULL值,这不总是一件坏事。 摘自MySQL 文档:
|
Robbie_Zhu
|
12. 预处理语句
使用预处理语句有诸多好处,包括更高的性能和更好的安全性。 预处理语句默认情况下会过滤绑定到它的变量,这对于避免SQL注入攻击极为有效。当然你也可以指定要过滤的变量。但这些方法更容易出现人为错误,也更容易被程序员遗忘。这在使用框架或 ORM 的时候会出现一些问题。 既然我们关注性能,那就应该说说这个方面的好处。当在应用中多次使用同一个查询的时候,它的好处特别明显。既然向同一个预备好的语句中传入不同的参数值,MySQL 对这个语句也只会进行一次解析。 同时,最新版本的 MySQL 在传输预备好的语句时会采用二进制形式,这样做的作用非常明显,而且对减少网络延迟很有帮助。 曾经有一段时间,许多程序员为了一个重要的原因则避免使用预处理语句。这个原因就是,它们不会被MySQL 缓存。不过在 5.1 版本的某个时候,查询缓存也得到的支持。 想在 PHP 中使用预处理语句,你可以看看 mysqli 扩展 或使用数据抽象层,如 PDO。
|
边城
|
13. 无缓冲查询
通常当你从脚本执行一个查询,在它可以继续后面的任务之前将需要等待查询执行完成。你可以使用无缓冲的查询来改变这一情况。 在PHP 文档中对 mysql_unbuffered_query() f函数有一个很好的解释:
然而,它有一定的局限性。你必须在执行另一个查询之前读取所有的行或调用mysql_free_result() 。另外你不能在结果集上使用mysql_num_rows() 或 mysql_data_seek() 。 |
Robbie_Zhu
|
14. 使用 UNSIGNED INT 存储IP地址
很多程序员没有意识到可以使用整数类型的字段来存储 IP 地址,所以一直使用 VARCHAR(15) 类型的字段。使用 INT 只需要 4 个字节的空间,而且字段长度固定。 必须确保列是 UNSINGED INT 类型,因为 IP 地址可能会用到 32 位无符号整型数据的每一个位。 在查询中可以使用 INET_ATON() 来把一个IP转换为整数,用 INET_NTOA() 来进行相反的操作。在 PHP 也有类似的函数,ip2long() 和 long2ip()。
|
边城
|
15. 固定长度(静态)的表会更快
(译者注:这里提到的表的长度,实际是指表头的长度,即表中每条数据占用的空间大小,而不是指表的数据量) 如果表中所有列都是“固定长度”,那么这个表被认为是“静态”或“固定长度”的。不固定的列类型包括 VARCHAR、TEXT、BLOB等。即使表中只包含一个这些类型的列,这个表就不再是固定长度的,MySQL 引擎会以不同的方式来处理它。 固定长度的表会提高性能,因为 MySQL 引擎在记录中检索的时候速度会更快。如果想读取表中的某一地,它可以直接计算出这一行的位置。如果行的大小不固定,那就需要在主键中进行检索。 它们也易于缓存,崩溃后容易重建。不过它们也会占用更多空间。例如,如果你把一个 VARCHAR(20) 的字符改为 CHAR(20) 类型,它会总是占用 20 个字节,不管里面存的是什么内容。 你可以使用“垂直分区”技术,将长度变化的列拆分到另一张表中。来看看: |
边城
|
17. 拆分大型DELETE或INSERT语句
如果你需要在网站上执行大型DELETE或INSERT查询,则需要注意不要影响网络流量。当执行大型语句时,它会锁表并使你的Web应用程序停止。 Apache运行许多并行进程/线程。 因此它执行脚本效率很高。所以服务器不期望打开过多的连接和进程,这很消耗资源,特别是内存。 如果你锁表很长时间(如30秒或更长),在一个高流量的网站,会导致进程和查询堆积,处理这些进程和查询可能需要很长时间,最终甚至使你的网站崩溃。 如果你的维护脚本需要删除大量的行,只需使用LIMIT子句,以避免阻塞。
|
snake_007
|
18. 越小的列越快
对于数据库引擎来说,磁盘空间可能是最需要注意的瓶颈。对性能而言,“小”和“紧缩”有助于减少磁盘传输量。 MySQL 文档中有一个列表,列举了各种数据类型所需要的存储空间。 如果数据表预计只会有少量的行,那就没必要把主键定义为 INT 类型,可以用 MEDIUMINT、SMALLINT 甚至 TINYINT 来代替。(译者注:对于日期数据,)如果不需要时间部分,就应该使用 DATE 而不是 DATETIME。 请确保留出合理的数据成长空间,不然就可能造成像Slashdot那样的结果(译者注:Slashdot 因为数据增长将评论表的主键改为了 INT 型,但没有修改其父表中的相应的数据类型,虽然一个 ALTER 语句就可以解决问题,但是需要至少停止某些业务三个小时)。 19. 选择正确的存储引擎MySQL 有两个主要的存储引擎:MyISAM 和 InnoDB,它们各有利弊。 MyISAM 适用于读请求特别多的应用,但不适用于有大量写请求的情况。甚至你只是要更新一行中的某个字段,都会造成整张表被锁,然后直到这个查询完成,其它进程都不能从这张表读取数据。MyISAM 在计算 SELECT COUNT(*) 这种类型的查询时速度非常快。 InnoDB 是一个复杂的存储引擎,在多数小型应用中它比 MyISAM 慢。但是它支持行级锁,有更好的尺度。它还支持一些高级特性,比如事务。 |
边城
|
其它翻译版本(1) |
20. 使用对象关系映射器(ORM, Object Relational Mapper)
通过使用ORM(对象关系映射器),你可以获得一定的性能提升。ORM可以完成的一切事情,手动编码也可完成。但这可能意味着需要太多额外的工作,并且需要高水平的专业知识。 |
Tocy
|
21. 小心使用持久连接
持久连接意味着减少重建连接到MySQL的成本。 当持久连接被创建时,它将保持打开状态直到脚本完成运行。 因为Apache重用它的子进程,下一次进程运行一个新的脚本时,它将重用相同的MySQL连接。
理论上看起来不错。 但从我个人(和许多其他人)的经验看来,这个功能可能会导致更多麻烦。 你可能会出现连接数限制问题、内存问题等等。 |