你如何优化这个MySQL慢查询?

时间:2011-11-14 18:08:49

标签: mysql sql query-optimization

表格

CREATE TABLE `deal_keyword` (
  `deal_id` int(11) NOT NULL default '0',
  `keyword_id` int(11) NOT NULL default '0',
  `area_id` int(11) NOT NULL default '0',
  PRIMARY KEY  (`deal_id`,`keyword_id`),
  KEY `area_id` (`area_id`,`keyword_id`,`deal_id`)
) TYPE=MyISAM

慢查询日志:

# Time: 111115  0:18:11
# Query_time: 2  Lock_time: 0  Rows_sent: 1  Rows_examined: 3629
select count(deal_id) from deal_keyword where area_id=101 && keyword_id=115;

# Time: 111115  0:34:55
# Query_time: 2  Lock_time: 0  Rows_sent: 1  Rows_examined: 5778
select count(deal_id) from deal_keyword where area_id=101 && keyword_id=142;

# Time: 111115  0:36:05
# Query_time: 3  Lock_time: 0  Rows_sent: 1  Rows_examined: 4433
select count(deal_id) from deal_keyword where area_id=101 && keyword_id=112;

# Time: 111115  0:36:06
# Query_time: 2  Lock_time: 0  Rows_sent: 1  Rows_examined: 1955
select count(deal_id) from deal_keyword where area_id=101 && keyword_id=533;

...

说明:

mysql> explain select count(deal_id) from deal_keyword where area_id=101 && keyword_id=115;
+--------------+------+---------------+---------+---------+-------------+------+--------------------------+
| table        | type | possible_keys | key     | key_len | ref         | rows | Extra                    |
+--------------+------+---------------+---------+---------+-------------+------+--------------------------+
| deal_keyword | ref  | area_id       | area_id |       8 | const,const | 4632 | Using where; Using index |
+--------------+------+---------------+---------+---------+-------------+------+--------------------------+
1 row in set (0.00 sec)

配置:

key_buffer=512M
max_allowed_packet=8M
table_cache=512
sort_buffer=8M
record_buffer=8M
thread_cache=8
thread_concurrency=4
myisam_sort_buffer_size=128M
interactive_timeout=28800
wait_timeout=7200

2 个答案:

答案 0 :(得分:4)

如果您的覆盖索引已经到位,则可能无法实现。原因如下:

运行以下查询:

SELECT COUNT(1) INTO @rowcount from deal_keyword;
SELECT FLOOR(COUNT(1) * 0.05) into @fivepct from deal_keyword;
SELECT @rowcount,@fivepct;
SELECT area_id,keyword_id,COUNT(1) paircount
FROM deal_keyword GROUP BY area_id,keyword_id
HAVING COUNT(1) >= @fivepct;

这些查询将显示哪些配对超过了deal_keyword表的总行数的5%。任何超过行数的5%的配对都将忽略MySQL查询优化器中索引的使用,并恢复为全表扫描。

请记住,由于该表是MyISAM,因此任何DML(INSERT,UPDATE或DELETE)都将执行完整的表锁。这将导致DML之后的deal_keyword表上的任何SELECT计数等待。此外,在任何DML之前的任何多个SELECT的突发都将使DML等待。

RECOMMEDATION:将表格转换为InnoDB

ALTER TABLE deal_keyword ENGINE=InnoDB;

针对InnoDB的计数将作为事务发生,并且不会阻止其他数据库连接执行计数。

答案 1 :(得分:0)

我怀疑它可以被优化。 一种丑陋的方式 - 您可以将当前计数存储在带有cols的单独表中: area_id | keyword_id |计数