一、MySQL简介
MySQL一般特制完整的MySQLRDBMS,是一个开源的关系型数据库管理系统(Relational Database Management System),现在属于Oracle公司。随着MySQL功能的不断完善,性能不断提高,又有开源免费的优势,越来越多的企业选择使用MySQL,而放弃商用收费的Oracle。
二、MySQL结构
1、逻辑结构
MySQL采用的是客户/服务器体系结构,因此实际使用时,有两个程序:
1. 一个是MySQL服务器程序,指的是mysqlId程序,运行在数据库服务器上,负责在网络上监听并处理来自客户端的服务请求根据这些请求去访问数据库的内容,再把有关信息回传给客户;
2. 另一个程序是MySQL客户端程序,负责连接到数据库服务器,并通过发出命令来告知服务器它想要的操作。
从下面简单的逻辑图中可以看出,MySQL内部大致分为三层:
1. 最上层是大部分基于网络的C/S服务都有的部分,比如连接处理、授权认证、安全等;
2. 第二层包括MySQL的很多核心服务功能,包括查询解析、分析、优化、缓存以及所有的内置函数(例如,日期、时间、数学和加密函数),所有的跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。
3. 第三层包含了存储引擎,存储引擎负责MySQL中欧数据的存储和提取,是数据库中非常重要非常核心的部分,也是MySQL区别与其他数据库的一个重要特性。
不同的存储引擎有个字的特点,MySQL支持插入式的存储引擎,可以根据实际情况选择最合适的存储引擎。不过目前对于绝大部分应用来说,MySQL默认的存储引擎InnoDB应该就是其最佳选择。我觉得刚开始学习的时候介绍很多不常用甚至不会用到的存储引擎虽然可能会横向比较,让开发人员更了解每个存储引擎的特性,但是这样对开发人员造成的困扰更大,还不如专心学习一种用途最广泛的存储引擎,屏蔽其他干扰,学到一定深度后再了解其他存储引擎的不同点。
2、体系结构
具体查看MySQL在物理上的体系结构,从上到下依次是:
1. 连接池组件
2. 管理服务和工具组件、SQL接口组件、查询分析器组件、优化器组件、缓冲组件
3. 插件式存储引擎
4. 物理文件
三、 数据库和实例
区分两个词
数据库指物理上的存储文件,实例是用来操作数据库文件的。在MySQL数据库中,实例与数据库通常是一一对应的,这时两个词可以互换,但在集群情况下,可能存在一个数据库被对个数据实例使用的情况.
MySQL是单进程多线程架构的数据库,实例在系统上的表现就是一个进程。
四、MySQL不得不说的八个陷阱
Mysql安装简单,速度较快,功能丰富。另外它还是开源运动的标杆,它的伟大成就向我们展示了一个成功的公司是可以建立在开源代码之上的。
然而用过mysql的人都曾对着显示器挥舞过拳头。但你不可能发明一种每秒能保存成千上万行互联网数据,并且一点错误都没有的技术吧。
以下列举了8个开源关系型数据库的缺陷,其中不仅限于MySQL,还有是针对关系型数据库的。只有明白了关系型数据库和MySQL,才能更好地避免在使用MySQL中尽量少地遇到一些意外。
1、根深蒂固的bugs
任何大的软件包都有 bug。但稍微深入了解一下,就会发现和 Mysql 相关的 bugs 自成体系。突然你就需要留心,因为 NULL 并不是以同样的方式出现,外键约束也没有像你想像的那样执行,连主键自动增长也会出错。
小问题大量存在,而且并不总是可以修复,这就是为什么一些人保持一个列表。还好 MySQL 维护着一个非常好的 bug 报告系统,让我们可以知道我些我们无法想像的事情,知道其他人也在经受同样的磨难。
2、关系表的不灵活性
关系表具有条理性,条理性是好的——但是,它使得程序员不得不编造或硬塞一些数据到已经定义好模式的列中。NoSQL开始越来越受到欢迎的原因之一,就是它为程序员提供了足够的灵活性,来加速数据库的使用。如果一个街道地址需要增加一行,那么,你可以将它很容易地插入到一个NoSQL文档中。如果你想添加一个完整的新的数据块,无论它包含什么内容,文档模型也可以原封不动地接受你的数据,而不必改为它要求的数据格式。
试想一下,你用整数格式建立了一个全部是邮编的表格。这个表是十分高效的,它执行的规则也很好。突然一次,有人上传了一个使用了连字符的九位数邮编。或者还有可能,你得到了一位来自加拿大客户的信件,上面写有邮政编码。
这时,一切都乱了。老板要求网站要在几小时内恢复正常工作。然而,现在已经没有时间来重建数据库。程序员可以做什么?也许,可以使用黑客手段把加拿大邮政编码由base64的数字格式改为base 10格式?或者设置一个使用转义编码的辅助表格,用来说明真正的邮政编码或者其他?谁知道呢?到处都有黑客,他们都是危险的。但你没有时间来搞定它。
MySQL的关联规则让每个人都诚实和谨慎,但它能强制我们避开易受攻击和欺骗的麻烦。
3、存储引擎混乱
总体来说,Mysql的存储引擎接口定义还算良好的。MySQL不是实际上的同一的数据库。它是由几个数据库组成,它们的大多数细节都被统一的表面掩盖了。开始时有一个MyISAM引擎,它很快但在前后一致上不能做到完备。有时你需要速度并且可以接受不一致的结果时是很好的。
当人们需要更多时,具备完整事务支持的Inno DB出现了。但这还不够。现在,它可能有20种存储引擎的选择——这足以使一个数据库管理员疯狂。当然,有时在不同的存储引擎之间切换而不必重写你的SQL是很好的,但是切换后总会带来混乱。这个表格我选择的引擎是MyISAM还是innoDB呢?或者,我决定输出的数据是CSV格式的吗?
4、JOIN联合查询
曾经,将数据分表保存是计算机科学史上的伟大创新。分开后的表不仅结构简单,使用上也简化了许多。但它却需要使用join语句来进行查询。
sql通过一系列join构建的复杂查询将开发者推入了困惑与绝望的深渊。而且存储引擎也需要以最优的方式来高效地解析join语句。开发者需要绞尽脑汁编写查询语句,然后数据库对其进行解析。
这就是很多注重运行速度的开发者放弃数据分表转而使用不规范数据表的原因。不区分数据实体,将所有数据保存到一个大表中——以避免复杂的查询。这样确实很快,并且服务器也不会耗尽内存。
现在的磁盘空间很廉价。8TB的磁盘已经在售,更大容量的也将上市。我们不再需要为使用join而绞尽脑汁了。
5、分支的混乱
毋庸置疑,一个可靠的、得到良好支持的MySQL分支,可以带来竞争和选择,但是它也引起困惑和混乱。更糟糕的是,一个称为MariaDB的MySQL分支,由Monty Widenius维护着。他同样也在参与编写MySQL。那么,Maria DB是真正独立的值得我们拥护的吗?或者它是MySQL?我们是否应该坚持使用由创建原始mysql数据库的组织运营的核心代码?或者我们应该加入那些被认为更聪明的,往往很酷的背叛者?
如何获取关于兼容性的信息?虽然Maria DB和MySQL十分相似,但它们之间也有差异。这就是大家一直都在争论它的原因。在性能方面,在我们查询的范围内,在两个阵营中,也许它们的工作方式相同,但也许不同,也许将来会不同。
6、开发MySQL的动机
虽然MySQL是一款成功的开源产品,但它仍属于商业中的一款产品,专业开发者需要靠它来获得利益,当然,最直接的利益就是薪资。当大多数用户在持续地享受开源许可证带来的最佳体验时,毫无疑问这家公司还在为赚取足够的钱来维持运营而努力。这导致自由代码在“社区版”和出售给企业的完整产品之间产生了奇怪的分岐。
我们应该对这款产品付钱吗?这种在社区版开展经营的行为是否公平?企业版中额外的功能是不是一个噱头,以引诱我们不断付费的呢?这至少说明一点,它是另一些需要回答的问题:选用哪个版本?遵照哪种许可证?选用它的哪个功能集?
7、原生JSON支持的缺乏
通过安装MySQL查看其年龄,然后你就知道需要添加哪些驱动程序使它变得可用。MySQL通常在3306端口上通信,一般输出的是它本身难以理解的格式化数据。如果要让你的代码和它通信,你必须添加另一层代码,将MySQL的语言转换成有用的东西。这些层的代码,以库的形式分发,经常需要人们购买一个商业许可证。
现代数据存储层通常直接以JSON通信。虽然MySQL和Maria DB现在有能力解析SQL中的JSON部分,但这还远远不够,原生的JSON接口已经被广泛使用于CouchDB、MongoDB,或任何最新的工具中。
8、封闭源和专有模块的兴起
虽然MySQL是开源的,但除了一些在”开源核心“周边开发的一些较新的、非开源的代码和专有模块。程序员也需要赚钱、需要生活,Oracle需要拿它的辛苦成果来换钱,这是一种现实,也是商业的性质。使用MySQL你也不可以免费得到任何东西。
要求MySQL始终坚持在一个很高的标准上,这有点不公平,因为开源的成功可能是一个圈套。它开始可以免费,但并不意味着它可以始终免费。如果企业需要更多新的功能,他们就要通过各种方式付费来获取。有时向Oracle付费,比自己来编写代码要便宜得多。有时商业的、不开源的代码是有意义的。
MySQL虽然作为一个成功的开源系统,但以上这些问题也总不可避免地出现,这就需要我们在它们发生之前有个深刻的认识,才能在今后的应用中避免不必要的麻烦。
在此我向大家推荐一个架构学习交流群。交流学习群号:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
五、MySQL分布式集群搭建
1 准备集群搭建环境
使用6台虚拟机来搭建MYSQL集群,相应的实验环境与对应的MYSQL节点之间的对应关系如下图所示:
管理节点(MGM):这类节点的作用是管理MySQLCluster内的其他节点,如提供配置数据,并停止节点,运行备份等。由于这类节点负责管理其他节点的配置,应该在启动其他节点之前启动这类节点。MGM节点是用命令“ndb_mgmd”启动的;
数据节点(NDB):这类节点用于保存Cluster的数据,数据节点的数目与副本的数目相关,是片段的倍数。例如,对于两个副本,每个副本有两个片段,那么就有4个数据节点,没有必要设定过多的副本,在NDB中数据会尽量的保存在内存中。数据节点使用命令“ndb”启动的;
SQL节点:这是用来访问Cluster数据的节点,对于MySQL Cluster,客户端节点是使用NDB Cluster存储引擎的传统MySQL服务器。通常,SQL节点使用命令“mysqld-ndbcluster”启动的;
2、准备安装包
在官网上下载mysql的安装包: mysql-cluster-gpl-7.4.11-Linux-glibc2.5-x86_64.tar.gz,并进行解压。
3、集群搭建流程
1]将上述安装包解压出来的文件都移到/usr/local/mysql下;
2]运行script目录下的mysql-install-db.sh脚本,运行命令为./mysql-install-db.sh --user=root--basedir =/usr/local/mysql --datadir=/usr/local/mysql;注意其中用户为root的名称需要跟配置文件my.cnf中的相同;
在管理节点,数据节点,SQL节点上都执行上述安装命令,从而完成对mysql的安装;
4、集群配置与启动
1]在管理节点上需要完成对于集群整体的配置配置:在/var/lib/mysql-cluster/config.ini中实现如下的配置信息:
2]在数据节点中需要在my.cnf中完成对于数据节点的相关配置信息,如下:
需要指明配置的数据节点的根目录,数据目录,socket连接配置,用户配置,以及对应的管理节点的ip地址配置;将配置完成的配置文件移动到/etc/my.cnf,完成;
3]在SQL节点上完成对于SQL节点的配置信息,同样的是在my.cnf中完成相应配置信息,并将配置文件移动到/etc/my.cnf中,相应的配置信息的设定如下所示:
完成以上配置后,就可以启动集群中的各个节点了。
5、集群启动
在启动mysql集群的时候,注意首先要启动管理节点,并依次启动其他等若干个节点,相应的启动步骤如下:
1]在管理节点上,切换到/usr/local/mysql/bin目录下,执行ndb_mgmd -f /var/lib/mysql-cluster/config.ini命令,完成管理节点的启动;
2]在各个数据节点上,切换到/usr/local/mysql/bin目录下,执行ndbd --initial(第一次启动时,否则执行ndbd即可),完成对数据节点的启动;
3]在各个SQL节点上,同样切换到/usr/local/mysql/bin目录下,执行mysqld_safe --user=root完成启动;
4]在管理节点上运行ndb_mgm命令,进入数据库管理的客户端,输入show命令,查看与之相连接的各个节点的状态;
5]在SQL节点上分别进入系统的安全状态,并完成对root用户的密码修改,运行以下指令,进行密码修改:
A use mysql,切换到mysql数据库;
B UPDATE user SET Password = PASSWORD('123456')WHERE user = 'root';从而实现对root密码的修改;
C flush privilege,完成修改;
6]修改使得任意主机都能连得上mysql,进行如下修改,同样安装第5步进入安全模式,并完成相应的修改,如下:
grant all on‘*.*’to ‘root@'%' identified by '123456';
这样就可以使得任意一个主机都可以通过root用户来登录mysql了;
6、集群测试
在集群上的一个SQL节点上执行创建数据库,并创建一张表,并完成相应的数据插入,如下:
A create database ctest; //创建数据库
B create table test(
id int primarykey; //创建一张表
);
C insert into test (id)values(1); //完成数据插入
登录另外一个SQL节点,并执行SQL查询操作,看数据库中是否已经有数据,如下:
select * from ctest;
如果有数据,表示数据插入成功;
7、关闭集群
1]首先关闭管理节点和数据节点,需要在管理节点上执行命令,如下:./ndb_mgm -e shutdown;
2]然后关闭SQL节点,在SQL节点上执行命令/usr/local/mysql/support-fies/mysql.server stop(其中/usr/local/mysql/是mysql的安装目录).从而关闭SQL节点
在此我向大家推荐一个架构学习交流群。交流学习群号:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
六、MySQL 的最佳实践
数据库操作是当今 Web 应用程序中的主要瓶颈。 不仅是 DBA(数据库管理员)需要为各种性能问题操心,程序员为做出准确的结构化表,优化查询性能和编写更优代码,也要费尽心思。 在本文中,我列出了一些针对程序员的 MySQL 优化技术。
在我们开始学习之前,我补充一点:你可以在 Envato Market 上找到大量的 MySQL 脚本和实用程序。
1.优化查询的查询缓存
大部分MySQL服务器都有查询缓存功能。这是提高性能的最有效的方法之一,这是由数据库引擎私下处理的。当同一个查询被多次执行,结果会直接从缓存里提取,这样速度就很快。
主要的问题是,这对程序员来说太简单了,不容易看到,我们很多人都容易忽略。我们实际上是可以组织查询缓存执行任务的。
查询缓存在第一行不执行的原因在于CURDTE()功能的使用。这适用于所有的非确定性功能,就像NOW()和RAND()等等。。。因为功能返回的结果是可变的。MySQL决定禁用查询器的查询缓存。我们所需要做的是通过添加一额外一行PHP,在查询前阻止它发生。
2. EXPLAIN你的选择查询
使用EXPLAIN关键词可以帮助了解MySQL是怎样运行你的查询的。这有助于发现瓶颈和查询或表结构的其它问题。
EXPLAIN的查询结果会展示哪一个索引被使用过,表示怎样扫描和储存的,等等。。。
选择一个SELECT查询(一个有连接的复杂查询会更好),在它的前面添加关键词EXPLAIN,这样就可以直接使用数据库了。结果会以一个漂亮的表来展示。例如,就好比我执行连接时忘了添加一栏的索引:
现在它只会从表2里面扫描9和16行,而非扫描7883行。经验法则是乘以所有“行”那一栏的数字,你的查询性能会跟结果数字成比例的。
3. 获取唯一行时使用LIMIT 1
有时当你查表时,你已经知道你正在查找的结果只有一行。你可能正在获取唯一记录,或者你可能只是查询是否存在满足你的WHERE子句条件的记录。
在这种情况下,将LIMIT 1添加到查询条件中可以提高性能。这样,数据库引擎将在找到刚刚第一个记录之后停止扫描记录,而不是遍历整个表或索引。
4. 索引搜索字段
索引不仅仅是为了主键或唯一键。如果你会在你的表中按照任何列搜索,你就都应该索引它们。
正如你所看到的,这个规则也适用于如 “last_name LIKE ‘a%’”的部分字符串搜索。当从字符串的开头搜索时,MySQL就可以使用那一列的索引。
你也应该明白什么样搜索可以不使用有规律的索引。例如,当搜索一个单词时(例如,”WHERE post_content LIKE ‘%apple%’”),你将不会看到普通索引的好处。你最好使用 mysql 全文搜索或者构建你自己的索引解决方案。
5. 索引并对连接使用同样的字段类型
如果你的应用程序包含许多连接查询, 你需要确保连接的字段在两张表上都建立了索引。 这会影响MySQL如何内部优化连接操作。
此外,被连接的字段,需要使用同样类型。例如, 如果你使用一个DECIMAL字段, 连接另一张表的INT字段, MySQL将无法使用至少一个索引。 即使字符编码也需要使用相同的字符类型。
6. 不要ORDER BY RAND()
起初这是一个听起来挺酷的技巧, 让许多菜鸟程序员陷入了这个陷阱。但你可能不知道,一旦你开始在查询中使用它,你创建了非常可怕的查询瓶颈。
如果你真的需要对结果随机排序, 这有一个更好的方法。补充一些额外代码,你将可以防止当数据成指数级增长时造成的瓶颈。关键问题是,MySQL必须在排序之前对表中的每一行执行RAND()操作(这需要处理能力),并且仅仅给出一行。
所以挑选一个小于结果数的随机数,并将其用作LIMIT子句中的偏移量。
7. 避免使用SELECT *
从数据表中读取的数据越多,查询操作速度就越慢。它增加了磁盘操作所需的时间。此外,当数据库服务器与Web服务器分开时,由于必须在服务器之间传输数据,将会有更长的网络延迟。
这是一个好习惯:当你使用SELECT语句时总是指定你需要的列。
8. 几乎总是有一个id字段
在每个以id列为PRIMARY KEY的数据表中,优先选择AUTO_INCREMENT或者INT。 也可以优选使用UNSIGNED,因为该值不能为负的。
即使你拥有一个具有唯一用户名字段的用户表,也不要将其作为主键。 VARCHAR字段作为主键(检索)速度较慢。通过内部ID引用所有的用户数据,你的代码中将更加结构化。
有些后台操作是由MySQL引擎本身完成的,它在内部使用主键字段。当数据库设置越复杂(集群,分区等…),这就变得更加重要了。
这个规则的一个可能的例外是“关联表”,用于两个表之间的多对多类型的关联。例如,“posts_tags”表中包含两列:post_id,tag_id,用于保存表名为“post”和“tags”的两个表之间的关系。这些表可以具有包含两个id字段的PRIMARY键。
9. 相比VARCHAR优先使用ENUM
ENUM枚举类型是非常快速和紧凑的。在内部它们像TINYINT一样存储,但它们可以包含和显示字符串值。这使他们成为某些领域的完美候选。
如果有一个字段只包含几种不同的值,请使用ENUM而不是VARCHAR。例如,它可以是名为“status”的列,并且只包含诸如“active”,“inactive”,“pending”,“expired”等的值…
关于如何重构你的数据表,甚至有一种方法是可以从MySQL本身得到“建议”。 当你有一个VARCHAR字段,它实际上建议你将该列类型更改为ENUM。这通过调用PROCEDURE ANALYZE()来完成。
在此我向大家推荐一个架构学习交流群。交流学习群号:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
10. 使用PROCEDURE ANALYSE()获取建议
PROCEDURE ANALYSE() 将使用MySQL分析列结构和表中的实际数据,为你提供一些建议。它只有在数据表中有实际数据时才有用,因为这在分析决策时很重要。
例如,如果你创建了一个INT类型的主键,但没有太多行,MySQL则可能建议您改用MEDIUMINT。或者如果你使用VARCHAR字段,如果表里只有很少的取值,你可能会得到一个建议是将其转换为ENUM。
你也可以在其中一个表视图中单击phpmyadmin中的“建议表结构”链接来执行此操作。
请记住,这些只是建议。 如果你的数据表变得越来越大,他们甚至可能不是正确的建议。至于如何修改最终是你来决定。
11. 如果可以的话使用NOT NULL
除非你有非常重要的理由使用NULL值,否则你应该设置你的列为NOT NULL。
首先,问一下你自己在空字符串值和NULL值之间(对应INT字段:0 vs. NULL)是否有任何的不同.如果没有理由一起使用这两个,那么你就不需要一个NULL字段(你知道在Oracle中NULL和空字符串是一样的吗?)。
NULL列需要额外的空间,他们增加了你的比较语句的复杂度。如果可以的话尽量避免它们。当然,我理解一些人,他们也许有非常重要的理由使用NULL值,这不总是一件坏事。
摘自MySQL 文档:
“行空列需要额外的空间来记录它们的值是否为空。 对于MyISAM表,每个NULL列需要一点额外的,围捕到最近的字节”。
12. 预处理语句
使用预处理语句有诸多好处,包括更高的性能和更好的安全性。
预处理语句默认情况下会过滤绑定到它的变量,这对于避免SQL注入攻击极为有效。当然你也可以指定要过滤的变量。但这些方法更容易出现人为错误,也更容易被程序员遗忘。这在使用框架或 ORM 的时候会出现一些问题。
既然我们关注性能,那就应该说说这个方面的好处。当在应用中多次使用同一个查询的时候,它的好处特别明显。既然向同一个预备好的语句中传入不同的参数值,MySQL 对这个语句也只会进行一次解析。
同时,最新版本的 MySQL 在传输预备好的语句时会采用二进制形式,这样做的作用非常明显,而且对减少网络延迟很有帮助。
曾经有一段时间,许多程序员为了一个重要的原因则避免使用预处理语句。这个原因就是,它们不会被MySQL 缓存。不过在 5.1 版本的某个时候,查询缓存也得到的支持。
想在 PHP 中使用预处理语句,你可以看看 mysqli 扩展 或使用数据抽象层,如 PDO。
13. 无缓冲查询
通常当你从脚本执行一个查询,在它可以继续后面的任务之前将需要等待查询执行完成。你可以使用无缓冲的查询来改变这一情况。
在PHP 文档中对 mysql_unbuffered_query() f函数有一个很好的解释:
“mysql_unbuffered_query()发送SQL查询查询MySQL没有自动抓取和缓冲结果行mysql_query()。 这节省了大量的内存生产大型结果集的SQL查询,你可以在结果集后立即开始工作第一行被检索到的是你不必等到完整的SQL查询已经完成。”
然而,它有一定的局限性。你必须在执行另一个查询之前读取所有的行或调用mysql_free_result() 。另外你不能在结果集上使用mysql_num_rows() 或 mysql_data_seek() 。
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 个字节,不管里面存的是什么内容。
你可以使用“垂直分区”技术,将长度变化的列拆分到另一张表中。来看看:
16. 垂直分区
垂直分区是为了优化表结构而对其进行纵向拆分的行为。
示例 1: 你可能会有一张用户表,包含家庭住址,而这个不是一个常用数据。这时候你可以选择把表拆分开,将住址信息保存到另一个表中。这样你的主用户表就会更小。如你所知,表越小越快。
示例 2: 表中有一个 “last_login” 字段,用户每次登录网站都会更新这个字段,而每次更新都会导致这个表缓存的查询数据被清空。这种情况下你可以将那个字段放到另一张表里,保持用户表更新量最小。
不过你也需要确保不会经常联合查询分开后的两张表,要不然你就得忍受由这带来的性能下降。
17. 拆分大型DELETE或INSERT语句
如果你需要在网站上执行大型DELETE或INSERT查询,则需要注意不要影响网络流量。当执行大型语句时,它会锁表并使你的Web应用程序停止。
Apache运行许多并行进程/线程。 因此它执行脚本效率很高。所以服务器不期望打开过多的连接和进程,这很消耗资源,特别是内存。
如果你锁表很长时间(如30秒或更长),在一个高流量的网站,会导致进程和查询堆积,处理这些进程和查询可能需要很长时间,最终甚至使你的网站崩溃。
如果你的维护脚本需要删除大量的行,只需使用LIMIT子句,以避免阻塞。
18.越少的列越快
对于数据库引擎,磁盘可能是最重要的瓶颈。更小更紧凑的数据、减少磁盘传输量,通常有助于性能提高。
MySQL文档Storage Requirements 有所有数据类型清单。
如果已知表具有很少的行,则没有理由是主键类型为INT,可以用MEDIUMINT、SMALLINT代替,甚至在某些情况下使用TINYINT。 如果不需要完整时间记录,请使用DATE而不是DATETIME。
确保留下合理的扩展空间,不然你可能会像Slashdot这样。
19. 选择正确的存储引擎
MySQL有两个主要存储引擎,MyISAM和InnoDB。 每个都有自己的优点和缺点。
MyISAM适用于读取繁重的应用程序,但是当有很多写入时它不能很好地扩展。 即使你正在更新一行的一个字段,整个表也被锁定,并且在语句执行完成之前,其他进程甚至无法读取该字段。 MyISAM在计算SELECT COUNT(*)的查询时非常快。
InnoDB是一个更复杂的存储引擎,对于大多数小的应用程序,它比MyISAM慢。 但它支持基于行的锁定,使其更好地扩展。 它还支持一些更高级的功能,比如事务。
● MyISAM存储引擎
● InnoDB存储引擎
20. 使用对象关系映射器(ORM, Object Relational Mapper)
通过使用ORM(对象关系映射器),你可以获得一定的性能提升。ORM可以完成的一切事情,手动编码也可完成。但这可能意味着需要太多额外的工作,并且需要高水平的专业知识。
ORM以“延迟加载”著称。这意味着它们仅在需要时获取实际值。但是你需要小心处理他们,否则你可能最终创建了许多微型查询,这会降低数据库性能。
ORM还可以将多个查询批处理到事务中,其操作速度比向数据库发送单个查询快得多。
目前我最喜欢的PHP-ORM是Doctrine。我写了一篇关于如何安装Doctrine与CodeIgniter的文章(install Doctrine with CodeIgniter)。
21. 小心使用持久连接
持久连接意味着减少重建连接到MySQL的成本。 当持久连接被创建时,它将保持打开状态直到脚本完成运行。 因为Apache重用它的子进程,下一次进程运行一个新的脚本时,它将重用相同的MySQL连接。
理论上看起来不错。 但从我个人(和许多其他人)的经验看来,这个功能可能会导致更多麻烦。 你可能会出现连接数限制问题、内存问题等等。
Apache总是并行运行的,它创建许多子进程。 这是持久连接在这种环境中不能很好工作的主要原因。 在你考虑使用mysql_pconnect()之前,请咨询你的系统管理员。