如何在MySQL中设置正确的索引或编写正确的查询?

时间:2018-07-08 19:24:19

标签: mysql indexing left-join

我有一个表,该表的唯一索引为(col1,col2,col3)

我对此表有一个查询

...
left join my_table t on t.col1=x.col1 and t.col2=x.col2 and t.col3 in (1,2,3)

当col3的列表中只有一项时,说明中会显示eq_ref join

+----+-------------+----------+------------+--------+---------------+-----+---------+---------------------+------+----------+-------+
| id | select_type |  table   | partitions |  type  | possible_keys | key | key_len |         ref         | rows | filtered | Extra |
+----+-------------+----------+------------+--------+---------------+-----+---------+---------------------+------+----------+-------+
|  1 | PRIMARY     | my_table | NULL       | eq_ref | veh           | veh |       8 | x.col1,x.col2,const |    1 |   100.00 | NULL  |
+----+-------------+----------+------------+--------+---------------+-----+---------+---------------------+------+----------+-------+

但是如果有两个或多个项目,则不再使用索引

+----+-------------+----------+------------+------+---------------+------+---------+------+----------+----------+------------------------------------------------+
| id | select_type |  table   | partitions | type | possible_keys | key  | key_len | ref  |   rows   | filtered |                     Extra                      |
+----+-------------+----------+------------+------+---------------+------+---------+------+----------+----------+------------------------------------------------+
|  1 | PRIMARY     | my_table | NULL       | ALL  | veh           | NULL | NULL    | NULL | 13705314 |   100.00 | Range checked for each record (index map: 0x3) |
+----+-------------+----------+------------+------+---------------+------+---------+------+----------+----------+------------------------------------------------+

col3上的另一个非唯一索引无济于事
我如何设置可以由这种join条件使用的索引?

或者我该如何重写查询?


编辑:其他信息

explain format=json
select x.*,ifnull(group_concat(t.col4 separator ','),'') col4
from
  (select col1,col2,total from tmp_data limit 10) x
  left join my_table t on t.col1=x.col1 and t.col2=x.col2 and t.col3 in (38,85)
group by x.col1,x.col2
order by x.total desc

{
 "query_block": {
   "select_id": 1,
   "cost_info": {
     "query_cost": "411271.71"
   },
   "ordering_operation": {
     "using_temporary_table": true,
     "using_filesort": true,
     "grouping_operation": {
       "using_filesort": true,
       "nested_loop": [
         {
           "table": {
             "table_name": "x",
             "access_type": "ALL",
             "rows_examined_per_scan": 10,
             "rows_produced_per_join": 10,
             "filtered": "100.00",
             "cost_info": {
               "read_cost": "10.50",
               "eval_cost": "2.00",
               "prefix_cost": "12.50",
               "data_read_per_join": "240"
             },
             "used_columns": [
               "col1",
               "col2",
               "total"
             ],
             "materialized_from_subquery": {
               "using_temporary_table": true,
               "dependent": false,
               "cacheable": true,
               "query_block": {
                 "select_id": 2,
                 "cost_info": {
                   "query_cost": "12.50"
                 },
                 "table": {
                   "table_name": "tmp_data",
                   "access_type": "ALL",
                   "rows_examined_per_scan": 10,
                   "rows_produced_per_join": 10,
                   "filtered": "100.00",
                   "cost_info": {
                     "read_cost": "10.50",
                     "eval_cost": "2.00",
                     "prefix_cost": "12.50",
                     "data_read_per_join": "5K"
                   },
                   "used_columns": [
                     "col1",
                     "col2",
                     "total"
                   ]
                 }
               }
             }
           }
         },
         {
           "table": {
             "table_name": "t",
             "access_type": "ALL",
             "possible_keys": [
               "veh",
               "col3"
             ],
             "rows_examined_per_scan": 13705314,
             "rows_produced_per_join": 320380,
             "filtered": "100.00",
             "range_checked_for_each_record": "index map: 0x3",
             "cost_info": {
               "read_cost": "347183.21",
               "eval_cost": "64076.00",
               "prefix_cost": "411271.71",
               "data_read_per_join": "7M"
             },
             "used_columns": [
               "col1",
               "col2",
               "col3",
               "col4"
             ]
           }
         }
       ]
     }
   }
 }
}

create table tmp_data 
(col1 mediumint(1) unsigned not null default 0,
 col2 mediumint(1) unsigned not null,
 total decimal(11,0) not null default 0,
 key veh (col1,col2) using hash
) engine=memory default charset=latin1 collate=latin1_general_ci

create table my_table
(col1 mediumint(1) unsigned not null,
 col2 mediumint(1) unsigned not null,
 col3 smallint(1) unsigned not null,
 col4 text collate latin1_general_ci,
 unique key veh (col1,col2,col3),
 key col3 (col3)
) engine=myisam default charset=latin1 collate=latin1_general_ci

1 个答案:

答案 0 :(得分:0)

  1. 使用InnoDB,而不是MyISAM或MEMORY。大多数Optimizer改进仅适用于InnoDB。 (注意:我没有证据证明这样做会有帮助。)

  2. 进行更改时,请将唯一键更改为PRIMARY KEY (col1,col2,col3)。 InnoDB PK的“聚集”性质应进一步提供帮助。 (此更改不会对MyISAM产生影响。)