Archive for 4月 26th, 2011

[难得技术] Mysql的索引测试与sql语句优化

星期二, 4月 26th, 2011

建立测试数据表

CREATE TABLE `milliontest` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT ,
`name` CHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
`content` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`time` INT( 11 ) NOT NULL DEFAULT '0',
`lastmodify` DATETIME NOT NULL,
PRIMARY KEY ( `id` )
) ENGINE = Myisam

用上面的语句创建一个测试用的表。表中包含5个字段,自增主键ID,标题名字name,内容content以及创建时间time与最后编辑时间lastmodify,其中time字段用时间戳而编辑时间为年月日格式。由于目前表内没有任何数据,接下来当然是往表里灌数据,灌上100W(唬人用)。

我写了一个php脚本来完成这个任务。代码如下,各位大大不要耻笑:

set_time_limit(0);
$conn = mysql_connect('localhost', 'root', '');
mysql_select_db('test');

$titles 	= array(
'任天堂3DS发售,2000RMB兲朝币',
 '明猪昨天买了飞行俱乐部', '前天第一次玩街霸网战虐人了!'
);
$contents	= array(
'据美国国家地理网站报道,美国“国家地理新闻”网站刊登了过去一周的精彩太空图片。
这些图片集中展现了极光、土卫一“米玛斯”、Abell 383星系团以及好似绿龙般的SH 
2-235星云等壮观景象',
'由于北极气候变暖,大量永冻土带融化,流入海洋。新研究发现,北极部分地区的永
久冻结带每年遭侵蚀的程度最多达到100英尺(约合30米)。');

$max = 1000000;
mysql_query("set names utf8");

for($i = 0; $i < $max; $i++) {
	$tn	= array_rand($titles);
	$cn	= array_rand($contents);
	$time	= time();
	$lastmodify = date('Y-m-d H:i:s');
	$res = mysql_query('insert into milliontest set name="'.$titles[$tn].'",
 content="'.$contents[$cn].'", time="'.$time.'", lastmodify="'.$lastmodify.'"');
	file_put_contents('million_log.txt', $i);
}

花了20多分钟时间数据库里终于有100w的数据了,泪流满面。那么下面就打开mysql终端开始华丽的测试一下。

select * from milliontest where time=1303812283;
/*略去搜索结果*/
146 rows in set (8.16 sec)

一条简单的查询就花了小小的8秒钟时间哦,要是100个人同时访问某个页面而同时运行了这条简单的语句,结果会怎么样咩? :s1hiahia

这里我又做了另一个测试,注意跟上面那条sql语句的区别:

select * from milliontest where time='1303812283';
/*略去搜索结果*/
146 rows in set (55.98 sec)

看到这查询时间,我自己都扭曲了,我只是查询一个想要的结果而已,却花56秒近1分钟的时间来等待查询。所以小提一下sql语句中各位注意一下引号吧。
又做了几组测试,时间多在8秒波动,有空各位自己慢慢测~

现在给time字段加一个索引

mysql> alter table milliontest add index (`time`);
Query OK, 1000000 rows affected (33.88 sec)
Records: 1000000  Duplicates: 0  Warnings: 0

建完索引,继续做一下上面的测试吧,嘻嘻。 :s1kila

mysql> select * from milliontest where time='1303812291';

615 rows in set (0.05 sec)

加了索引后这次花了0.05秒,相对之前的数据,速度提升相当多吧哈哈哈。不过这么简单的查询却花了0.05秒,对于并发量大的时候估计也不乐观咩,咱们试试去掉引号?

mysql> select * from milliontest where time=1303812283;

146 rows in set (0.00 sec)

爽吧!花费时间0.00! :s1nihaha

体会到了索引带来的好处了吧,不过话说我突然想起来,跑去看了一下这张表占的磁盘容量,泪流满面我没找到wamp这个软件吧索引文件丢到哪去了,总之之前我在自己ubuntu下做的测试好像加表数据占了磁盘800M还是多少,忘了

分页的SQL优化(limit优化)

之前在网上看的时候看到很多关于limit优化的文章,不小心看到一篇分页优化,哎哟看完那篇文章之后,我突然恍然大悟,附我跟主管的某段对话:

主管:好像现在后台有点慢?
我:估计是数据正在批量入库的缘故,不快。

但事后我重新测试了下后台,速度还是NN慢。刚好想到某篇分页测试的文章,提到:
select id,name from milliontest limit 0,20;的速度与select id,name from milliontest limit N,20;
不一样,查询结果的速度取决于N,也就是N越大,速度越慢。
嘴巴说没什么用,还是看事实。

mysql> select id,name from milliontest limit 0,20;
20 rows in set (0.00 sec)
而
mysql> select id,name from milliontest limit 100000,20;
20 rows in set (0.25 sec)
再看
mysql> select id,name from milliontest limit 500000,20;
20 rows in set (1.05 sec)

明显查询时间有了小增长吧。后面的时间更恐怖哟。所以很多论坛之类的,数据太久的就不显示出来了,或者加缓存,那是其他的技术咯。 (更多…)