非常慢的mysql查询:左连接多个表和每个表的where子句

时间:2014-06-25 14:52:24

标签: mysql sql

我有一个基表(id表)和多个表(数据表),它们具有与id相关的数据,并且每个表都有不同的类型数据。 我想从这些不同的表中按多个条件过滤id。

我创建了如下查询,但这太慢了,就像3分钟一样。我检查了解释信息,但仍然找不到更好的方法。有没有人能找到让它更快的方法?

查询

    select jj.id, jj.imgtitle, jj.alias
    from jjtable jj
    inner join jjtable_catg jjc on jj.catid = jjc.cid
    left join jjtable_map jjtm_name on jj.id = jjtm_name.picid
    left join jjtable_tags jjts_name on jjtm_name.tid = jjts_name.tid
    left join jjtable_map_ge jjtm_ge on jj.id = jjtm_ge.picid
    left join jjtable_tags jjts_ge on jjtm_ge.tid = jjts_ge.tid
    left join jjtable_map_ban jjtm_ban on jj.id = jjtm_ban.picid
    left join jjtable_tags jjts_ban on jjtm_ban.tid = jjts_ban.tid
    left join jjtable_map_per jjtm_per on jj.id = jjtm_per.picid
    left join jjtable_tags jjts_per on jjtm_per.tid = jjts_per.tid
    left join jjtable_map_fea jjtm_fea on jj.id = jjtm_fea.picid
    left join jjtable_tags jjts_fea on jjtm_fea.tid = jjts_fea.tid
    left join jjtable_map_ev jjtm_ev on jj.id = jjtm_ev.picid
    left join jjtable_tags jjts_ev on jjtm_ev.tid = jjts_ev.tid 
    left join jjtable_map_ag jjtm_ag on jj.id = jjtm_ag.picid
    left join jjtable_tags jjts_ag on jjtm_ag.tid = jjts_ag.tid
    left join jjtable_map_fa jjtm_fa on jj.id = jjtm_fa.picid
    left join jjtable_tags jjts_fa on jjtm_fa.tid = jjts_fa.tid
    left join jjtable_map_im jjtm_im on jj.id = jjtm_im.picid
    left join jjtable_tags jjts_im on jjtm_im.tid = jjts_im.tid where jj.published = 1
    and jj.approved  = 1 
    and jjts_fea.tid in(87,90)
    and jjts_fea.delete_flag = 0
    and jjtm_fea.delete_flag = 0
    and jjc.cid in(4,10)
    and jjts_name.tid in(77)
    and jjts_name.delete_flag = 0
    and jjtm_name.delete_flag = 0
    and jjts_per.tid in(28,36)
    and jjts_per.delete_flag = 0
    and jjtm_per.delete_flag = 0
    and jjts_ag.tid in(98,99)
    and jjts_ag.delete_flag = 0
    and jjtm_ag.delete_flag = 0
    and jjts_fa.tid in(104,107)
    and jjts_fa.delete_flag = 0
    and jjtm_fa.delete_flag = 0 
    group by jj.id 
    order by case when date(jj.date) > date_add(date(now()), interval -14 day) then jj.view end DESC, jj.id DESC
编辑:谢谢你的评论。首先,我根据您的要求添加信息。

为什么需要这个查询;

此查询旨在从"表单输入"中接收帖子数据。标记哪个用户从不同类别中选择选项以过滤ID。这就是为什么此查询包含本示例中未使用的表和数据的原因。

左边连接数太多的原因是每个地图都有' table具有用于过滤ID的类别映射信息。等等,用户想要找到与' fea',90,90和' ag',99,99映射的ID。

解释选择;

        +----+-------------+--------------+--------+-------------------+-----------------+---------+------------------------------------------------+------+---------------------------------+
        | id | select_type | table        | type   | possible_keys     | key             | key_len | ref                                            | rows | Extra                           |
        +----+-------------+--------------+--------+-------------------+-----------------+---------+------------------------------------------------+------+---------------------------------+
        |  1 | SIMPLE      | jjts_name    | const  | PRIMARY           | PRIMARY         | 4       | const                                          |    1 | Using temporary; Using filesort |
        |  1 | SIMPLE      | jjc          | range  | PRIMARY           | PRIMARY         | 4       | NULL                                           |    2 | Using where                     |
        |  1 | SIMPLE      | jjts_pe      | range  | PRIMARY           | PRIMARY         | 4       | NULL                                           |    2 | Using where; Using join buffer  |
        |  1 | SIMPLE      | jjts_fea     | range  | PRIMARY           | PRIMARY         | 4       | NULL                                           |    2 | Using where; Using join buffer  |
        |  1 | SIMPLE      | jjts_ag      | range  | PRIMARY           | PRIMARY         | 4       | NULL                                           |    2 | Using where; Using join buffer  |
        |  1 | SIMPLE      | jjts_fa      | range  | PRIMARY           | PRIMARY         | 4       | NULL                                           |    2 | Using where; Using join buffer  |
        |  1 | SIMPLE      | jj           | ref    | PRIMARY,idx_catid | idx_catid       | 4       | jjc.cid                                        |   95 | Using where                     |
        |  1 | SIMPLE      | jjtm_ag      | eq_ref | udx_picid_tid     | udx_picid_tid   | 8       | jj.id,jjts_ag.tid                              |    1 | Using where                     |
        |  1 | SIMPLE      | jjtm_fa      | eq_ref | udx_picid_tid     | udx_picid_tid   | 8       | jj.id,jjts_fa.tid                              |    1 | Using where                     |
        |  1 | SIMPLE      | jjtm_fea     | eq_ref | udx_picid_tid     | udx_picid_tid   | 8       | jj.id,jjts_fea.tid                             |    1 | Using where                     |
        |  1 | SIMPLE      | jjtm_pe      | eq_ref | udx_picid_tid     | udx_picid_tid   | 8       | jjtm_fea.picid,jjts_per.tid                    |    1 | Using where                     |
        |  1 | SIMPLE      | jjtm_ev      | ref    | udx_picid_tid     | udx_picid_tid   | 4       | jjtm_fa.picid                                  |    3 | Using index                     |
        |  1 | SIMPLE      | jjts_ev      | eq_ref | PRIMARY           | PRIMARY         | 4       | jjtm_ev.tid                                    |    1 | Using index                     |
        |  1 | SIMPLE      | jjtm_im      | ref    | udx_picid_tid     | udx_picid_tid   | 4       | jjtm_pe.picid                                  |    6 | Using index                     |
        |  1 | SIMPLE      | jjts_im      | eq_ref | PRIMARY           | PRIMARY         | 4       | jjtm_im.tid                                    |    1 | Using index                     |
        |  1 | SIMPLE      | jjtm_ge      | ref    | udx_picid_tid     | udx_picid_tid   | 4       | jj.id                                          |   23 | Using index                     |
        |  1 | SIMPLE      | jjts_ge      | eq_ref | PRIMARY           | PRIMARY         | 4       | jjtm_ge.tid                                    |    1 | Using index                     |
        |  1 | SIMPLE      | jjtm_ban     | ref    | udx_picid_tid     | udx_picid_tid   | 4       | jjtm_pe.picid                                  |    9 | Using index                     |
        |  1 | SIMPLE      | jjts_ban     | eq_ref | PRIMARY           | PRIMARY         | 4       | jjtm_ban.tid                                   |    1 | Using index                     |
        |  1 | SIMPLE      | jjtm_name    | eq_ref | udx_picid_tid     | udx_picid_tid   | 8       | jjtm_fea.picid,const                           |    1 | Using where                     |
        +----+-------------+--------------+--------+-------------------+-----------------+---------+------------------------------------------------+------+---------------------------------+
        20 rows in set (2 min 15.87 sec)

显示列;

        mysql> show columns from jjtables;
        +--------------+------------------+------+-----+---------+----------------+
        | Field        | Type             | Null | Key | Default | Extra          |
        +--------------+------------------+------+-----+---------+----------------+
        | id           | int(11)          | NO   | PRI | NULL    | auto_increment |
        | catid        | int(11)          | NO   | MUL | 0       |                |
        | imgtitle     | text             | NO   |     | NULL    |                |
        | alias        | varchar(255)     | NO   |     |         |                |
        | date         | datetime         | NO   |     | NULL    |                |
        | view         | int(11)          | NO   |     | 0       |                |
        | published    | tinyint(1)       | NO   |     | 0       |                |
        | approved     | tinyint(1)       | NO   |     | 0       |                |
        +--------------+------------------+------+-----+---------+----------------+


        mysql> show columns from jjtable_catg;
        +--------------+---------------------+------+-----+---------+----------------+
        | Field        | Type                | Null | Key | Default | Extra          |
        +--------------+---------------------+------+-----+---------+----------------+
        | cid          | int(11)             | NO   | PRI | NULL    | auto_increment |
        | name         | varchar(255)        | NO   |     |         |                |
        | alias        | varchar(255)        | NO   |     |         |                |
        | parent       | int(11)             | NO   | MUL | 0       |                |
        | desc         | text                | YES  |     | NULL    |                |
        | order        | int(11)             | NO   |     | 0       |                |
        +--------------+---------------------+------+-----+---------+----------------+


        mysql> show columns from jjtable_tags;
        +--------------+-------------+------+-----+---------------------+----------------+
        | Field        | Type        | Null | Key | Default             | Extra          |
        +--------------+-------------+------+-----+---------------------+----------------+
        | tid          | int(11)     | NO   | PRI | NULL                | auto_increment |
        | name         | varchar(60) | NO   | UNI | NULL                |                |
        | talias       | varchar(60) | NO   |     |                     |                |
        | ttypeid      | int(11)     | NO   |     | 1                   |                |
        | pa_tid       | int(11)     | NO   |     | 0                   |                |
        | delete_flag  | tinyint(1)  | NO   |     | 0                   |                |
        | created      | datetime    | NO   |     | 0000-00-00 00:00:00 |                |
        | created_by   | int(11)     | NO   |     | 0                   |                |
        | modified     | datetime    | NO   |     | 0000-00-00 00:00:00 |                |
        | modified_by  | int(11)     | NO   |     | 0                   |                |
        | t_due        | datetime    | NO   |     | 0000-00-00 00:00:00 |                |
        +--------------+-------------+------+-----+---------------------+----------------+


        mysql> show columns from jjtable_map;
        +-------------+------------+------+-----+---------------------+----------------+
        | Field       | Type       | Null | Key | Default             | Extra          |
        +-------------+------------+------+-----+---------------------+----------------+
        | id          | int(11)    | NO   | PRI | NULL                | auto_increment |
        | picid       | int(11)    | NO   | MUL | NULL                |                |
        | tid         | int(11)    | NO   |     | NULL                |                |
        | delete_flag | tinyint(1) | NO   |     | 0                   |                |
        | created     | datetime   | NO   |     | 0000-00-00 00:00:00 |                |
        | created_by  | int(11)    | NO   |     | 0                   |                |
        | modified    | datetime   | NO   |     | 0000-00-00 00:00:00 |                |
        | modified_by | int(11)    | NO   |     | 0                   |                |
        +-------------+------------+------+-----+---------------------+----------------+

很抱歉我的解释不好。我希望这个编辑有助于您更好地理解。 编辑结束 此致

3 个答案:

答案 0 :(得分:3)

一个很大的改进是在连接处使用多个条件而不是获得一个巨大的集合然后将条件放在最后。我的意思是,如果你同时加入条件你加入你的套装会更小,你的响应时间会更好:

 select jj.id, jj.imgtitle, jj.alias
    from jjtable jj
    inner join jjtable_catg jjc on jj.catid = jjc.cid 
    left join jjtable_map jjtm_name on jj.id = jjtm_name.picid and jjtm_name.delete_flag = 0
    ...

答案 1 :(得分:3)

试试这个:将您的左连接转换为一堆WHERE EXISTS个子查询,然后删除GROUP BY,因为(这是我怀疑的)这就是你的真实内容想要表达。

select 
    jj.id, jj.imgtitle, jj.alias
from 
    jjtable jj
    -- you could drop this join, you don't do anything with jjtable_catg
    inner join jjtable_catg jjc on jjc.cid = jj.catid
where
    jj.published = 1
    and jj.approved  = 1 
    and jjc.cid in(4, 10)
    and exists (
      select 1 
      from jjtable_map m inner join jjtable_tags t on m.tid = t.tid 
      where m.picid = jj.id m.delete_flag = 0 and t.tid in (77) and t.delete_flag = 0
    )
    and exists (
      select 1 
      from jjtable_map_per m inner join jjtable_tags t on m.tid = t.tid 
      where m.picid = jj.id m.delete_flag = 0 and t.tid in (28,36) and t.delete_flag = 0
    )
    and exists (
      select 1 
      from jjtable_map_fea m inner join jjtable_tags t on m.tid = t.tid 
      where m.picid = jj.id m.delete_flag = 0 and t.tid in (87,90) and t.delete_flag = 0
    )
    and exists (
      select 1 
      from jjtable_map_ag m inner join jjtable_tags t on m.tid = t.tid 
      where m.picid = jj.id m.delete_flag = 0 and t.tid in (98,99) and t.delete_flag = 0
    )
    and exists (
      select 1 
      from jjtable_map_fa m inner join jjtable_tags t on m.tid = t.tid 
      where m.picid = jj.id m.delete_flag = 0 and t.tid in (104,107) and t.delete_flag = 0
    )
order by 
    case when date(jj.date) > date_add(date(now()), interval -14 day) then jj.view end DESC, 
    jj.id DESC

同时创建这些复合索引(如果它们缺失):

  • jjtable_catg(cid)
  • jjtable_tags(tid, delete_flag)
  • jjtable_map以及所有jjtable_map_*(picid, delete_flag, tid)

答案 2 :(得分:0)

此查询已经有很多表。删除任何未使用的表。这种联接有什么理由吗?

left join jjtable_map_im jjtm_im on jj.id = jjtm_im.picid
left join jjtable_tags jjts_im on jjtm_im.tid = jjts_im.tid where jj.published = 1

根本没有使用jjtm_im和jjts_im。