MYSQL explain详解
explain显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。
先解析一条sql语句,看出现什么内容
EXPLAINSELECTs.uid,s.username,s.name,f.email,f.mobile,f.phone,f.postalcode,f.address
FROM uchome_space ASs,uchome_spacefieldASf
WHERE 1
AND s.groupid=0
AND s.uid=f.uid
1. id
SELECT识别符。这是SELECT查询序列号。这个不重要,查询序号即为sql语句执行的顺序,看下面这条sql
EXPLAINSELECT*FROM(
SELECT* FROMuchome_space LIMIT10)ASs
它的执行结果为
可以看到这时的id变化了
2.select_type
select类型,它有以下几种值
2.1 simple 它表示简单的select,没有union和子查询
2.2 primary 最外面的select,在有子查询的语句中,最外面的select查询就是primary,上图中就是这样
2.3 union union语句的第二个或者说是后面那一个.现执行一条语句,explain
select * from uchome_space limit 10 union select * from uchome_space limit 10,10
会有如下结果
第二条语句使用了union
2.4 dependent union UNION中的第二个或后面的SELECT语句,取决于外面的查询
2.5 union result UNION的结果,如上面所示
还有几个参数,这里就不说了,不重要
3 table
输出的行所用的表,这个参数显而易见,容易理解
4 type
连接类型。有多个参数,先从最佳类型到最差类型介绍 重要且困难
4.1 system
表仅有一行,这是const类型的特列,平时不会出现,这个也可以忽略不计
4.2 const
表最多有一个匹配行,const用于比较primary key 或者unique索引。因为只匹配一行数据,所以很快
记住一定是用到primary key 或者unique,并且只检索出两条数据的 情况下才会是const,看下面这条语句
explain SELECT * FROM `asj_admin_log` limit 1,结果是
虽然只搜索一条数据,但是因为没有用到指定的索引,所以不会使用const.继续看下面这个
explain SELECT * FROM `asj_admin_log` where log_id = 111
log_id是主键,所以使用了const。所以说可以理解为const是最优化的
4.3 eq_ref
对于eq_ref的解释,mysql手册是这样说的:"对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用于使用=比较带索引的列。看下面的语句
explain select * from uchome_spacefield,uchome_space where uchome_spacefield.uid = uchome_space.uid
得到的结果是下图所示。很明显,mysql使用eq_ref联接来处理uchome_space表。
目前的疑问:
4.3.1 为什么是只有uchome_space一个表用到了eq_ref,并且sql语句如果变成
explain select * from uchome_space,uchome_spacefield where uchome_space.uid = uchome_spacefield.uid
结果还是一样,需要说明的是uid在这两个表中都是primary
4.4 ref 对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。
看下面这条语句 explain select * from uchome_space where uchome_space.friendnum = 0,得到结果如下,这条语句能搜出1w条数据
4.5 ref_or_null 该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。
上面这五种情况都是很理想的索引使用情况
4.6 index_merge 该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。
4.7 unique_subquery
4.8 index_subquery
4.9 range 给定范围内的检索,使用一个索引来检查行。看下面两条语句
explain select * from uchome_space where uid in (1,2)
explain select * from uchome_space where groupid in (1,2)
uid有索引,groupid没有索引,结果是第一条语句的联接类型是range,第二个是ALL.以为是一定范围所以说像 between也可以这种联接,很明显
explain select * from uchome_space where friendnum = 17
这样的语句是不会使用range的,它会使用更好的联接类型就是上面介绍的ref
4.10 index 该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。(也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
当查询只使用作为单索引一部分的列时,MySQL可以使用该联接类型。
4.11 ALL 对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。
5 possible_keys 提示使用哪个索引会在该表中找到行,不太重要
6 keys MYSQL使用的索引,简单且重要
7 key_len MYSQL使用的索引长度
8 ref ref列显示使用哪个列或常数与key一起从表中选择行。
9 rows 显示MYSQL执行查询的行数,简单且重要,数值越大越不好,说明没有用好索引
10 Extra 该列包含MySQL解决查询的详细信息。
10.1 Distinct MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。一直没见过这个值
10.2 Not exists
10.3 range checked for each record
没有找到合适的索引
10.4 using filesort
MYSQL手册是这么解释的“MySQL需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行。”目前不太明白
10.5 using index 只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的信息。这个比较容易理解,就是说明是否使用了索引
explain select * from ucspace_uchome where uid = 1的extra为using index(uid建有索引)
explain select count(*) from uchome_space where groupid=1 的extra为using where(groupid未建立索引)
10.6 using temporary
为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列的GROUP BY和ORDER BY子句时。
出现using temporary就说明语句需要优化了,举个例子来说
EXPLAIN SELECT ads.id FROM ads, city WHERE city.city_id = 8005 AND ads.status = 'online' AND city.ads_id=ads.id ORDER BY ads.id desc
id select_type table type possible_keys key key_len ref rows filtered Extra
------ ----------- ------ ------ -------------- ------- ------- -------------------- ------ -------- -------------------------------
1 SIMPLE city ref ads_id,city_id city_id 4 const 2838 100.00 Using temporary; Using filesort
1 SIMPLE ads eq_ref PRIMARY PRIMARY 4 city.ads_id 1 100.00 Using where
这条语句会使用using temporary,而下面这条语句则不会
EXPLAIN SELECT ads.id FROM ads, city WHERE city.city_id = 8005 AND ads.status = 'online' AND city.ads_id=ads.id ORDER BY city.ads_id desc
id select_type table type possible_keys key key_len ref rows filtered Extra
------ ----------- ------ ------ -------------- ------- ------- -------------------- ------ -------- ---------------------------
1 SIMPLE city ref ads_id,city_id city_id 4 const 2838 100.00 Using where; Using filesort
1 SIMPLE ads eq_ref PRIMARY PRIMARY 4 city.ads_id 1 100.00 Using where
这是为什么呢?他俩之间只是一个order by不同,MySQL 表关联的算法是 Nest Loop Join,是通过驱动表的结果集作为循环基础数据,然后一条一条地通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。EXPLAIN 结果中,第一行出现的表就是驱动表(Important!)以上两个查询语句,驱动表都是 city,如上面的执行计划所示!
1)指定了联接条件时,满足查询条件的记录行数少的表为[驱动表];
2)未指定联接条件时,行数少的表为[驱动表](Important!)。
永远用小结果集驱动大结果集
今天学到了一个很重要的一点:当不确定是用哪种类型的join时,让mysql优化器自动去判断,我们只需写select * from t1,t2 where t1.field = t2.field
10.7 using where
WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值不为Using where并且表联接类型为ALL或index,查询可能会有一些错误。(这个说明不是很理解,因为很多很多语句都会有where条件,而type为all或index只能说明检索的数据多,并不能说明错误,useing where不是很重要,但是很常见)
如果想要使查询尽可能快,应找出Using filesort 和Using temporary的Extra值。
10.8 Using sort_union(...), Using union(...),Using intersect(...)
这些函数说明如何为index_merge联接类型合并索引扫描
10.9 Using index for group-by
类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于每个组,只读取少量索引条目。
实例讲解
通过相乘EXPLAIN输出的rows列的所有值,你能得到一个关于一个联接如何的提示。这应该粗略地告诉你MySQL必须检查多少行以执行查询。当你使用max_join_size变量限制查询时,也用这个乘积来确定执行哪个多表SELECT语句。
LNMP一键安装包
系统需求:
- CentOS/RHEL/Fedora/Debian/Ubuntu/Raspbian Linux系统
- 需要3GB以上硬盘剩余空间
- 128M以上内存,Xen的需要有SWAP,OpenVZ的另外至少要有128MB以上的vSWAP或突发内存(小内存请勿使用64位系统),MySQL 5.6及MariaDB 10必须1G以上内存。
- VPS或服务器必须已经联网,同时VPS/服务器 DNS要正常!
- Linux下区分大小写,输入命令时请注意!
安装步骤:
1、使用putty或类似的SSH工具登陆VPS或服务器;
登陆后运行:screen -S lnmp
如果提示screen: command not found 命令不存在可以执行:yum install screen 或 apt-get install screen安装,详细的screen教程。
您可以选择使用下载版(推荐国外或者美国VPS使用)或者完整版(推荐国内VPS使用),两者没什么区别,只是完整版把一些需要的源码文件预先放到安装包里。
安装LNMP执行:wget -c http://soft.vpser.net/lnmp/lnmp1.2-full.tar.gz && tar zxf lnmp1.2-full.tar.gz && cd lnmp1.2-full && ./install.sh lnmp
如需要安装LNMPA或LAMP,将./install.sh 后面的参数替换为lnmpa或lamp即可。
如下载速度慢请更换其他下载节点,详情请看下载页面。LNMP下载节点具体替换方法。
按上述命令执行后,会出现如下提示:
需要设置MySQL的root密码(不输入直接回车将会设置为root),输入后回车进入下一步,如下图所示:
这里需要确认是否启用MySQL InnoDB,如果不确定是否启用可以输入 y ,输入 y 表示启用,输入 n 表示不启用。默认为y 启用,输入后回车进入下一步,选择MySQL版本:
输入MySQL或MariaDB版本的序号,回车进入下一步,选择PHP版本:
输入PHP版本的序号,回车进入下一步,选择是否安装内存优化:
可以选择不安装、Jemalloc或TCmalloc,输入对应序号回车。
如果是LNMPA或LAMP的话还需要设置管理员邮箱
再选择Apache版本
提示"Press any key to install...or Press Ctrl+c to cancel"后,按回车键确认开始安装。
LNMP脚本就会自动安装编译Nginx、MySQL、PHP、phpMyAdmin、Zend Optimizer这几个软件。
安装时间可能会几十分钟到几个小时不等,主要是机器的配置网速等原因会造成影响。
3、安装完成
如果显示Nginx: OK,MySQL: OK,PHP: OK
并且Nginx、MySQL、PHP都是running,80和3306端口都存在,并Install lnmp V1.2 completed! enjoy it.的话,说明已经安装成功。
接下来按添加虚拟主机教程,添加虚拟主机,通过sftp或ftp服务器上传网站,将域名解析到VPS或服务器的IP上,解析生效即可使用。
4、安装失败
如果出现类似上图的提示,则表明安装失败,说明没有安装成功!!需要用winscp或其他类似工具,将/root目录下面的lnmp-install.log下载下来,到LNMP支持论坛发帖注明你的系统发行版名称及版本号、32位还是64位等信息,并将lnmp-install.log压缩以附件形式上传到论坛,我们会通过日志查找错误,并给予相应的解决方法。
5、添加、删除虚拟主机及伪静态管理
http://lnmp.org/faq/lnmp-vhost-add-howto.html
6、eAccelerator、xcache、memcached、imageMagick、ionCube、redis、opcache的安装
http://lnmp.org/faq/addons.html
7、LNMP相关软件目录及文件位置
http://lnmp.org/faq/lnmp-software-list.html
8、LNMP状态管理命令
http://lnmp.org/faq/lnmp-status-manager.html
简洁优雅的命令行工具 homebrew-cask
简洁优雅的命令行工具 homebrew-cask
使用homebrew-cask安装软件,只需要一行命令
brew cask install sublime-text skitch dropbox google-chrome
这样以下就安装了4个软件,轻松搞定,不需要鼠标点击,no dragging, no dropping。
* 命令行?好像很高大上的赶脚,我能学会吗? *
homebrew-cask是一套建立在homebrew基础上的Mac软件安装命令行工具(想要详细了解homebrew,自己google)。拥有她只需要简单的3步:
- 安装Xcode(Mac App Store免费一键下载)
- 安装homebrew(一行命令直接搞定,easy)
- 安装homebrew-cask(也是一行命令搞定,一点难度都木有)
不要一听到是命令行
就被吓到,其实没有那么复杂,命令行
你就简单理解为你输入一行一行指令,指令对了系统就会去执行,用狗血的拟人比喻,就是你让计算机去干活,只要命令
下得对,它就屁颠屁颠卖命去了。
1. 安转Xcode
Xcode安装现在已经非常简单,打开「Mac App Store」,又上角搜索 xcode
就可以找到,点击安装,耗时较长耐心等待。
这一步是鼠标操作,很简单,就这样跳过了。
2. 安装homebrew
homebrew的官网是http://brew.sh/,上面有简体版本,可以了解以下homebrew是干啥的,但回到安装的正题,一行命令安装:
先打开 Terminal
,找不到的可以点击Mac屏幕右上角的放大镜(这货是传说中的Spotlight),然后输入terminal
回车就能直接打开。
打开Terminal
后,把下面的一样命令复制粘贴到里面,按下回车:
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
屏幕一堆英文乱闪之后,就搞定了(命令提示符号回到原来的样子)。
3. 安装homebrew-cask
还是那个「Terminal」窗口,再把下面的命令复制粘贴过去,按下回车。
brew tap phinze/homebrew-cask && brew install brew-cask
在安装brew-cask的时候,会要求你输入当前用户的密码,输入过程中不会有屏幕反馈,你就闭着眼睛输入,然后回程就可以。
又一大波文字乱闪,OK啦。
如何使用homebrew-cask
需要安装应用时,打开「Terminal」,输入
brew cask install XXX # 将XXX替换成你想要安装的软件名称就可以了
下面做个示范:
* 常用命令 *
brew cask search
列出所有可以被安装的软件brew cask search drop
查找所有和 drop 相关的应用brew cask info thunder
查看 迅雷 应用的信息,这货安装的可是最新版本的迅雷哦!brew cask uninstall qq
卸载 QQ
特别注意 homebrew-cask是将应用程序放置在
/opt/homebrew-cask/Caskroom/
下,会在你的家目录中的「应用程序」文件夹中创建一个类似快捷方式的替身。在Finder的偏好设置中,第三个侧边栏勾选上你的家目录,这样找应用会方便一些。但不用太担心你,Launchpad是会找到这个目录下的应用的,需要Alfred支持请查看brew cask alfred
。
homebrew-cask vs Mac App Store
homebrew-cask 和 Mac App Store 相比,目前还有很多优势:
- 安装软件体验非常一致简洁优雅
- 对常用软件支持更全面,例如 MPlayerX 已经宣布不在更新 Mac App Store上 的版本
- 软件更新速度快,体验好。例如Alfred 2.0已经出了很久,但在 Mac App Store 上还是1.2版本,QQ也是这样的情况
当然我承认,命令行的交互方式并不是人人都能学会和接受,homebrew-cask其实已经做的足够简单易用,习得这一技能能在以后提高效率。homebrew-cask安装省时省力,更新应用也简单,不用一个一个去找,其实先花时间学习,是值回本钱的,大家自己算算这笔帐。
Mac App Store 生态圈远不完善,审核流程过长,限制太多,维护成本过高让很多应用开发者被迫离开。虽然我个人很喜欢 homebrew-cask,但还是希望 Apple 尽快完善 Mac App Store ,等到有一天我可以不再使用 homebrew-cask。这样说是不是显得我很薄情?:)
关于软件更新
homebrew-cask团队一直还在探讨软件更新策略,以及homebrew-cask与homebrew的关系。目前倾向于:
- homebrew-cask作为软件安装工具体验是不错的(相比你要自己到网页上搜索,下载,拖转安装)
- 大部分软件都有自更新的功能,体验也不错,绝大多数只需要一次点击就能更新
- 实际上软件更新没有那么频繁,使用
brew cask uninstall qq && brew cask install qq
也比上网自己下载更新方便
软件更新的结论
目前通过homebrew-cask安装的软件有两种更新方法:
- 使用软件自己的更新流程
brew cask uninstall APP && brew cask install APP
先删除App,再重新安装
详细情况可以围观这个讨论帖子: brew cask upgrade, 具体看 第2条 和 第5条 评论。
一键装机?有了homebrew-cask就可以
# 到目前October 5, 2013 1:43 PM为止,homebrew-cask共收录566款应用程序 # 瞬间安装所有常用软件 brew cask install alfred brew cask install the-unarchiver brew cask install qq brew cask install line brew cask install skype brew cask install thunder brew cask install mplayerx brew cask install evernote brew cask install skitch brew cask install dropbox brew cask install google-chrome brew cask install mou brew cask install iterm2 brew cask install sublime-text brew cask install virtualbox
Nginx和PHP-FPM的启动/重启脚本
服务器上的Nginx和PHP都是源码编译安装的,不支持类似以前的nginx (start|restart|stop|reload)了。自己动手丰衣足食。以下脚本应该在RHEL, Fedora, CentOS下都适用。
一、Nginx启动脚本/etc/init.d/nginx
#!/bin/bash
#
# Startup script for Nginx - this script starts and stops the nginx daemon
#
# chkconfig:
# description:
# processname: nginx
# config:
# pidfile:
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
nginx="/usr/local/nginx/sbin/nginx"
prog=$(basename $nginx)
NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile=/var/lock/subsys/nginx
start() {
}
stop() {
}
restart() {
}
reload() {
}
force_reload() {
}
configtest() {
}
rh_status() {
}
rh_status_q() {
}
case "$1" in