사용자 SQL 느린 조회 분석, 원인 및 최적화

7326 단어 MySQL
문제 설명
          SQL            。SQL        (              ):
SELECT count(*)  FROM  a  JOIN  b ON  a.`S` = b.`S` WHERE a.`L` > '2014-03-30 00:55:00' AND a.`L` < '2014-03-30 01:00:00' ; 

             ,     :
CREATE TABLE `a` (
  `L` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00',
  `I` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `A` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `S` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `F` tinyint(4) DEFAULT NULL,
  `V` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '',
  `N` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  KEY `IX_L` (`L`),
  KEY `IX_I` (`I`),
  KEY `IX_S` (`S`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `b` (
  `R` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00',
  `V` varchar(32) DEFAULT NULL,
  `U` varchar(32) DEFAULT NULL,
  `C` varchar(16) DEFAULT NULL,
  `S` varchar(64) DEFAULT NULL,
  `I` varchar(64) DEFAULT NULL,
  `E` bigint(32) DEFAULT NULL,
  `ES` varchar(128) DEFAULT NULL,
  KEY `IX_R` (`R`),
  KEY `IX_C` (`C`),
  KEY `IX_S` (`S`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    ,          ,      a     ,     a.L b.S     。    explain     :
    +----+-------------+-------+-------+---------------+------+---------+----------+---------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref      | rows    | Extra       |
+----+-------------+-------+-------+---------------+------+---------+----------+---------+-------------+
|  1 | SIMPLE      | b     | index | IX_S          | IX_S | 195     | NULL     | 1038165 | Using index |
|  1 | SIMPLE      | a     | ref   | IX_L,IX_S     | IX_S | 195     | test.b.S |       1 | Using where |
+----+-------------+-------+-------+---------------+------+---------+----------+---------+-------------+

분석하다.
 explain    ,    b     。
          ,MySQL  jion         join      ,         。
  join       ,    optimizer_search_depth  。         ,       join           ?

MySQL Tips: MySQL  straight_join  ,        。

explain SELECT count(*)  FROM  a  straight_join  b ON  a.`S` = b.`S` WHERE a.`L` > '2014-03-30 00:55:00' AND a.`L` < '2014-03-30 01:00:00' ;            
+----+-------------+-------+-------+---------------+------+---------+------+---------+---------------------------------------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows    | Extra                                       |
+----+-------------+-------+-------+---------------+------+---------+------+---------+---------------------------------------------+
|  1 | SIMPLE      | a     | range | IX_L,IX_S     | IX_L | 4       | NULL |      63 | Using where                                 |
|  1 | SIMPLE      | b     | index | IX_S          | IX_S | 195     | NULL | 1038165 | Using where; Using index; Using join buffer |
+----+-------------+-------+-------+---------------+------+---------+------+---------+---------------------------------------------+
MySQL Tips: explain   ,join            rows  。
join    ,         :  join 1038165*1, straight_join  63*1038165.   MySQL   。       !

이상을 발견하다
         。     a     ,      b    IX_S  ,    staight_join        ,              。
    ,                             ,     b.S       ?
MySQL Tips: show index from tbname     Cardinality              。
show index     ,    information_schema   。
mysql> select * from information_schema.STATISTICS where table_name='b' and index_name='IX_S'\G
*************************** 1. row ***************************
TABLE_CATALOG: def
 TABLE_SCHEMA: test
   TABLE_NAME: b
   NON_UNIQUE: 1
 INDEX_SCHEMA: test
   INDEX_NAME: IX_S
 SEQ_IN_INDEX: 1
  COLUMN_NAME: S
    COLLATION: A
  CARDINALITY: 1038165
     SUB_PART: NULL
       PACKED: NULL
     NULLABLE: YES
   INDEX_TYPE: BTREE
      COMMENT: 
INDEX_COMMENT: 

       CARDINALITY: 1038165,     。            。
show table status like 'b'\G
*************************** 1. row ***************************
           Name: b
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1038165
 Avg_row_length: 114
    Data_length: 119160832
Max_data_length: 0
   Index_length: 109953024
      Data_free: 5242880
 Auto_increment: NULL
    Create_time: 2014-05-23 00:24:25
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options: 
        Comment: 
1 row in set (0.00 sec)
 Rows: 1038165  ,IX_S              ,         。

MySQL Tips:  show table status      Rows          。  MyISAM        ,  InnoDB      。

      ,           ,    ,     explain            :staight_join       rows。

현재까지
               : a         ,    b.S rows   1038165            b    。
             1.
(   explan            ,    type   Extra       )

    ,straight_join       b      ,       。 MySQL                  。         ,         ,                。

   case  ,       。  ,        。
       ,  S          COLLATE utf8_bin --      case      :a    S  utf8_bin,         ,        b.IX_S  。

           ,           “  ”。
MySQL Tips:                   ,               。
    ,
mysql> explain SELECT *  FROM  a  straight_JOIN  b ON  binary a.`S` = b.`S` WHERE a.`L` > '2014-03-30 00:55:00' AND a.`L` < '2014-03-30 01:00:00' ;        

+—-+————-+——-+——-+—————+——+———+——+———+————————————————+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +—-+————-+——-+——-+—————+——+———+——+———+————————————————+ | 1 | SIMPLE | a | range | IX_L | IX_L | 4 | NULL | 63 | Using where | | 1 | SIMPLE | b | ALL | IX_S | NULL | NULL | 1038165 | Range checked for each record (index map: 0x4) | + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(필자 눈물: 이 결과가 일찍 나왔으면 조사하기가 훨씬 편했을 텐데.)
최적화
                S     ,      。              , DDL    。       SQL       。

1、select count(*) from  b join (select s from  a  WHERE a.`L` > '2014-03-30 00:55:00' AND a.`L` < '2014-03-30 01:00:00') ta on b.S=ta.s;
        ,      b.S ta.S   

2、SELECT count(*)  FROM  a  JOIN  b ON  binary a.`S` = b.`S` WHERE a.`L` > '2014-03-30 00:55:00' AND a.`L` < '2014-03-30 01:00:00' ;
           b.S   utf8_bin.
MySQL Tips: MySQL         , XXX_bin XXX           。
     A.s    binary  ,     ,          utf8_bin,    b.S            。
             ,     1     。      2     。

소결
 join              。

좋은 웹페이지 즐겨찾기