OC

Knowledge OS
主帖 24 条回复

一句Sql语句的优化(带子查询)

tinyfool tinyfool · 2013年11月20日 · 阅读 0 · 无人欣赏。
SELECT * FROM `threads` where `createbyid` <> 24016 AND `id` in (SELECT `threadid` FROM `thread_replys` WHERE `userid` = 24016 GROUP BY `threadid`); 

这么一句sql,要想高效,应该怎么写?

回复

24 条
#1
coredump
2013年11月20日

试试用join: SELECT t.* FROM threads t inner join thread_replys r ON t.id = r.threadid where t.createbyid <> 24016 AND r.userid = 24016;

#4
terryso
2013年11月20日

2楼 @tinyfool 我觉得首先要看看执行计划,找出查询慢的瓶颈。 另外检查看看有没有针对相关字段做索引。。。

#6
tinyfool
2013年11月20日

3楼 @fanngyuan

CREATE TABLE `threads` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL DEFAULT '',
  `content` blob NOT NULL,
  `createby` varchar(50) NOT NULL DEFAULT '',
  `createbyid` int(11) NOT NULL,
  `lastreply` varchar(50) NOT NULL DEFAULT '',
  `lastreplyid` int(11) NOT NULL DEFAULT '0',
  `createdate` int(11) NOT NULL,
  `updatedate` int(11) NOT NULL,
  `replys` int(11) NOT NULL,
  `modifydate` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1540 DEFAULT CHARSET=utf8;
#7
coredump
2013年11月20日

2楼 @tinyfool 看看你的SQL运行的执行计划,index是不是使用正常(特别是那个createdbyid有没有索引?)。 一般来说用IN都会较慢,因为内部查询不结束外部查询无法开始。

#8
贵人
2013年11月20日

4楼 @terryso 对,支持楼上,最好先看看执行计划,如果有必要,可以在id上加索引,并且将索引的查询条件放在where条件的最前面

#9
coredump
2013年11月20日

如果记录数很大MyISAM engine也应该考虑换成其它的

#10
tinyfool
2013年11月20日

createbyid也加上索引了,没有发现明显变化

#11
coredump
2013年11月20日

话说,你的数据库的确有点点点点慢,发表一个回复要等等等等等等等等等好久久久久

#12
tinyfool
2013年11月20日

11楼 @coredump 就是这句话闹的,锁表了

# Query_time: 114.958171  Lock_time: 0.000077 Rows_sent: 1  Rows_examined: 27389215
SET timestamp=1384932679;
SELECT * FROM `threads` where `createbyid` <> 22734 AND `id` in (SELECT `threadid` FROM `thread_replys` WHERE `userid` = 22734 GROUP BY `threadid`);
#14
tinyfool
2013年11月20日

EXPALIN的结果

mysql> explain
    -> SELECT * FROM `threads` where `createbyid` <> 24016 AND `id` in (SELECT `threadid` FROM `thread_replys` WHERE `userid` = 24016 GROUP BY `threadid`); 
+----+--------------------+---------------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type        | table         | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
+----+--------------------+---------------+-------+---------------+----------+---------+------+------+-------------+
|  1 | PRIMARY            | threads       | ALL   | createbyid    | NULL     | NULL    | NULL | 1505 | Using where |
|  2 | DEPENDENT SUBQUERY | thread_replys | index | NULL          | threadid | 5       | NULL |    6 | Using where |
+----+--------------------+---------------+-------+---------------+----------+---------+------+------+-------------+
2 rows in set (0.00 sec)
#16
coredump
2013年11月20日

threads表的问题: 1. content不应该嵌入在threads表里,单独成content表,thread里放content_id 2. createdby和replyedby用户名其实也不应该存在threads表里

threads和reply表记录数无疑会很多,这就要求这两个表的设计应该尽可能轻量。

如果不重新改表结构的话,你先试试把SELECT t.*改成SELECT t.id, 然后用另一组SQL再单独取出thread的具体内容。

#17
tinyfool
2013年11月20日

给thread_replys的userid加上索引后,正常了

#18
fanngyuan
2013年11月20日

thread表建立 id-createbyid 的联合索引,thread_replys 建立userid-threadid 的联合索引

#20
gb18030
2013年11月20日

第一关键是不要select *,只select自己需要的字段,合理加上index

#21
灵感之源
2013年11月21日

17楼 @tinyfool

终于做了我的建议。。别的技术我不打包票,数据库性能我还是有信心的。。。。

#24
Joey
2013年11月25日

SELECT `threadid` FROM `thread_replys` WHERE `userid` = 24016 GROUP BY `threadid`

猜测使用group By是想要去重后的threadid,如果是这样的话可以改为

select distinct `threadid` FROM `thread_replys` WHERE `userid` = 24016 试试,理论上会快一些,如果userId是主键或者有索引就更好了

本帖有24个回复,因为您没有注册或者登录本站,所以只能看到本帖的10条回复。如果想看到全部回复,请注册或者登录本站。
登录 或者 注册
顶楼 / 底楼 / 首页