簡體   English   中英

奇怪的mysql查詢執行時間行為

[英]Strange mysql query execution time behavior

你好,我在幾乎相同的SQL查詢中有一個奇怪的執行時間行為

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之差在t1 module列,也位於where語句中

我只是看不出問題出在哪里,請別人anyone我

更新

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)

看着那,我認為原因就像是由於INNODB Buffer Pool 第一個查詢從一個干凈的緩沖區開始,因此在處理查詢之前,它需要將索引讀入內存。 然后,當您運行第二個查詢時,它已經在內存中,因此運行速度要快得多。

嘗試在每個查詢之間添加FLUSH TALBES命令。

您也可以嘗試使用Benchmark()函數對此進行測試。

可能造成差異的另一件事是要傳輸的數據大小。 我看到附加列聲明為VARCHAR(255) 也許該列中包含大量數據,並且9000行確實確實增加了網絡開銷,從而大大增加了網絡開銷。

至少要調查一些事情...

基於針對其他答案的討論,以及增加的非緩存,不太可能與任何緩存有關。 這些計划也完全相同,因此沒有朝那個方向發展。

因此,最可能的原因與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;

收集所涉及的varchar的總長度

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM