百度空间 | 百度首页 
 
查看文章
 
改变了对Mysql子查询的看法
2008-11-04 15:31
最开始使用SQLServer,我喜欢这么用SQL:select * from table1 where id in (select table1_id from table2 where table2_filed = xxxx) and table1_field = yyy; 这里的一个查询其实会分为两个查询,对table1和对table2的子查询,这样写能让每个查询都尽量使用索引。

   曾几何时,使用mysql的时候用explain分析查询,发现mysql里面的子查询很慢,而mysql文档里很多时候也推荐使用join,于是我认定了mysql的子查询实现的很烂,以后的程序里面都用join了。例如上面的查询我就写成:select a.* from table1 a join table2 b on b.table2_field=xxx and b.table1_id=a.id where a.table1_field = yyy;

   今天早上,接到一个电话,说ucdchina.com挂了。上去一看,一个表被管理员rename了,理由是涉及这个表的查询太耗时了,平均40s左右。我只能说,dreamhost实在太烂了,两个表总共不到2000条数据,怎么也不用那么久来查吧。我拿到管理员发出的慢查询,用explain看了一下,果然use filesort,use temporary file,SQL语法就是类似上面join那个例子。然后我根据查询里的字段建了两个索引,但是没效果。最后习惯性的尝试了一下子查询,把上面join的那个格式修改为in的方式,explain 的结果马上变成use index; use where。终于又对mysql的in恢复了信心。

   优化了ucdchina.com的将近10条语句,整个网站速度快多了。

类别:数据库 | 添加到搜藏 | 浏览() | 评论 (10)
 
最近读者:
 
网友评论:
1
2008-11-04 18:23 | 回复
呵呵,上次面试的时候,那个人和我说,你怎么还用左联接,那个效率挺低的。当时也没整明白。看来一切还得explain说了算。 以前一看见子查询就觉得不好,看来这种看法也要有所改变了。
 
2
2008-11-04 20:28 | 回复
mysql 5.0.45,数据比较多的时候 select * from table1 where id in (select table1_id from table2 where table2_filed = xxxx) and table1_field = yyy; 比 select * from table1,(select table1_id from table2 where table2_filed = xxxx) t2 where table1.id=t2.table1.id) and table1_field = yyy; 要慢得多,哪怕select table1_id from table2 where table2_filed = xxxx出来的结果挺少. 把表结构和sql贴出来看下啊
 
3
2008-11-04 20:52 | 回复
文章中的那个sql例子基本上包含了两个表的关键字段 table1 => article表,id为主键 table2 => category_article_relation表,category_id和article_id联合主键 在这里join是没用索引的 两个表量级相当,目前1000左右
 
4
2008-11-04 20:56 | 回复
join要在关键on条件的字段上建好索引, 然后把其他条件放到where里,并且考虑on条件和where条件里字段的联合索引,这样可能好点。 如果有order by,情况更复杂。mysql的查询优化能力还是差点,要靠人为设计简单的结构和查询才行。
 
5
2008-11-04 23:18 | 回复
CREATE TABLE `article` ( `id` bigint(20) NOT NULL auto_increment, `title` varchar(255) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `category` ( `id` bigint(20) NOT NULL auto_increment, `name` varchar(255) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `category_article_relation` ( `article_id` bigint(20) NOT NULL default '0', `category_id` bigint(20) NOT NULL default '0', `id` bigint(20) NOT NULL auto_increment, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
6
2008-11-04 23:19 | 回复
cat insert_data.sh #!/bin/bash echo -n >insert.sql for i in `seq 0 9` do echo "replace into category set id=$i,name='c-$i';" >>insert.sql for j in `seq 1 200` do let ARTICLE_ID=$i*200+$j echo "replace into article set id=$ARTICLE_ID,title='t-$ARTICLE_ID';" >>insert.sql echo "replace into category_article_relation set id=$ARTICLE_ID,article_id=$ARTICLE_ID,category_id=$i;" >>insert.sql done done mysql -uroo test
 
7
2008-11-04 23:19 | 回复
sql: select * from article a join category_article_relation r on r.article_id=a.id and r.category_id=0 where a.title like 't-%' order by a.id desc explain select * from article a join category_article_relation r on r.article_id=a.id and r.category_id=0 where a.title like 't-%' order by a.id desc\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: r type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1124 Extra: Using where; Using temporary; Using filesort *************************** 2. row *************************** id: 1 select_type: SIMPLE table: a type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: test.r.article_id rows: 1 Extra: Using where 虽然explain结果是这样,但查询还是0.00秒。 只能说在这种数据量下慢是系统资源太少太少.
 
8
2008-11-04 23:20 | 回复
加个索引 mysql> alter table category_article_relation add index idx_car_article_id (article_id); Query OK, 2000 rows affected (0.17 sec) Records: 2000 Duplicates: 0 Warnings: 0 mysql> explain select * from article a join category_article_relation r on r.article_id=a.id and r.category_id=0 where a.title like 't-%' order by a.id desc\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: a type: index possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: NULL rows: 1958 Extra: Using where *************************** 2. row *************************** id: 1 select_type: SIMPLE table: r type: ref possible_keys: idx_car_article_id key: idx_car_article_id key_len: 8 ref: test.a.id rows: 1 Extra: Using where 2 rows in set (0.00 sec)
 
9
2008-11-05 11:29 | 回复
总共就2000的数据,怎么都不会慢的。 怀疑是dreamhost对数据库配置特殊,可能对filesort和临时表限制很死
 
10
2008-11-15 15:57 | 回复
不能吧!1000条记录还有优化的余地,真是世事难料。
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu