奇怪的mysql查询执行时间行为

时间:2011-01-25 02:04:36

标签: sql mysql

您好 我在几乎相同的SQL查询上有一个奇怪的执行时间行为

Q 1:

SELECT `t1`.`id`, `t1`.`key`, `t1`.`module`, `t2`.`value` 
FROM `translates` AS `t1` 
LEFT JOIN `translates_i18n` AS `t2` ON (`t2`.`id` = `t1`.`id` AND `t2`.`culture` = 'en') 
WHERE `t1`.`module` IN ('GLOBAL','AJAX','FORMS', .... about 15 items) LIMIT 9000;

0.10秒

Q2:

SELECT `t1`.`id`, `t1`.`key`, `t2`.`value` 
FROM `translates` AS `t1` 
LEFT JOIN `translates_i18n` AS `t2` ON (`t2`.`id` = `t1`.`id` AND `t2`.`culture` = 'en') 
WHERE `t1`.`module` IN ('GLOBAL','AJAX','FORMS', .... about 15 items) LIMIT 9000;

0.000 ...秒

表定义:

CREATE TABLE IF NOT EXISTS `translates` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `key` varchar(255) NOT NULL,
  `module` varchar(255) NOT NULL,
  `system` tinyint(3) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `key` (`key`,`module`),
  KEY `module` (`module`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;

CREATE TABLE IF NOT EXISTS `translates_i18n` (
  `id` int(11) unsigned NOT NULL,
  `culture` varchar(2) NOT NULL,
  `value` text NOT NULL,
  PRIMARY KEY (`id`,`culture`),
  KEY `culture` (`culture`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


ALTER TABLE `translates_i18n`
  ADD CONSTRAINT `translates_i18n_ibfk_1` FOREIGN KEY (`id`) REFERENCES `translates` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
q1&之间的区别q2位于t1module列中,也位于where语句

我只是看不出问题出在哪里,拜托,任何人都会把我弄死。

更新

Q 1:

mysql> EXPLAIN SELECT SQL_NO_CACHE  `t1`.`id` ,  `t1`.`key` ,  `t1`.`module` ,  `t2`.`value` 
    -> FROM  `translates` AS  `t1` 
    -> LEFT JOIN  `translates_i18n` AS  `t2` ON (  `t2`.`id` =  `t1`.`id` 
    -> AND  `t2`.`culture` =  'en' ) 
    -> WHERE  `t1`.`module` 
    -> IN (
    -> 'GLOBAL',  'AJAX',  'FORMS',  'ROOTMENU',  'LANGSWITCHER',  'AUTHORIZATION',  'MENU',  'MINIFY',  'SIMPLESHOP'
    -> )
    -> LIMIT 100500
    -> ;
+----+-------------+-------+--------+-----------------+---------+---------+---------------------+------+--------------------------+
| id | select_type | table | type   | possible_keys   | key     | key_len | ref                 | rows | Extra                    |
+----+-------------+-------+--------+-----------------+---------+---------+---------------------+------+--------------------------+
|  1 | SIMPLE      | t1    | index  | module          | key     | 1534    | NULL                |  627 | Using where; Using index |
|  1 | SIMPLE      | t2    | eq_ref | PRIMARY,culture | PRIMARY | 12      | theloom.t1.id,const |    1 |                          |
+----+-------------+-------+--------+-----------------+---------+---------+---------------------+------+--------------------------+
2 rows in set (0.00 sec)

Q2:

mysql> EXPLAIN SELECT SQL_NO_CACHE  `t1`.`id` ,  `t1`.`key` ,  `t2`.`value` 
    -> FROM  `translates` AS  `t1` 
    -> LEFT JOIN  `translates_i18n` AS  `t2` ON (  `t2`.`id` =  `t1`.`id` 
    -> AND  `t2`.`culture` =  'en' ) 
    -> WHERE  `t1`.`module` 
            -> IN (
    -> 'GLOBAL',  'AJAX',  'FORMS',  'ROOTMENU',  'LANGSWITCHER',  'AUTHORIZATION',  'MENU',  'MINIFY',  'SIMPLESHOP'
    -> )
    -> LIMIT 100500;
+----+-------------+-------+--------+-----------------+---------+---------+---------------------+------+--------------------------+
| id | select_type | table | type   | possible_keys   | key     | key_len | ref                 | rows | Extra                    |
+----+-------------+-------+--------+-----------------+---------+---------+---------------------+------+--------------------------+
|  1 | SIMPLE      | t1    | index  | module          | key     | 1534    | NULL                |  627 | Using where; Using index |
|  1 | SIMPLE      | t2    | eq_ref | PRIMARY,culture | PRIMARY | 12      | theloom.t1.id,const |    1 |                          |
+----+-------------+-------+--------+-----------------+---------+---------+---------------------+------+--------------------------+
2 rows in set (0.00 sec)

2 个答案:

答案 0 :(得分:3)

考虑到这一点,我认为原因就像是the INNODB Buffer Pool。第一个查询以干净缓冲区开始,因此在它处理查询之前,它需要将索引读入内存。然后当你运行第二个查询时,它已经在内存中,所以运行得更快。

尝试在每个查询之间添加FLUSH TALBES命令。

您也可以尝试使用Benchmark()功能对此进行测试。

可能导致差异的另一件事是要传输的数据的大小。我看到附加列被声明为VARCHAR(255)。是否该列有大量数据,9000行确实会显着增加网络开销......

至少要研究一些事情......

答案 1 :(得分:0)

基于对其他答案的讨论以及无缓存的添加,它不太可能与任何缓存有任何关系。计划完全相同,所以没有任何方向。

因此,最可能的原因是检索和存储varchar(255)列。

尝试这3个新查询,看看你得到了什么:

仅计算长度,仍然稍微处理模块列

SELECT `t1`.`id`, `t1`.`key`, Length(`t1`.`module`), `t2`.`value` 
FROM `translates` AS `t1` 
LEFT JOIN `translates_i18n` AS `t2` ON (`t2`.`id` = `t1`.`id` AND `t2`.`culture` = 'en') 
WHERE `t1`.`module` IN ('GLOBAL','AJAX','FORMS', .... about 15 items) LIMIT 9000;

仅测试掩码是否为空

SELECT `t1`.`id`, `t1`.`key`, case when `t1`.`module` is null then 1 else 0 end, `t2`.`value` 
FROM `translates` AS `t1` 
LEFT JOIN `translates_i18n` AS `t2` ON (`t2`.`id` = `t1`.`id` AND `t2`.`culture` = 'en') 
WHERE `t1`.`module` IN ('GLOBAL','AJAX','FORMS', .... about 15 items) LIMIT 9000;

收集所涉及的varchars的总长度

SELECT Length(GROUP_CONCAT(module))
FROM
(
    SELECT `t1`.`id`, `t1`.`key`, `t1`.`module`, `t2`.`value` 
    FROM `translates` AS `t1` 
    LEFT JOIN `translates_i18n` AS `t2` ON (`t2`.`id` = `t1`.`id` AND `t2`.`culture` = 'en') 
    WHERE `t1`.`module` IN ('GLOBAL','AJAX','FORMS', .... about 15 items) LIMIT 9000
) X