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

非常慢的mysql查询:左键连接多个表和每个表的where子句,mysql,sql,Mysql,Sql,我有一个基表(id表)和多个表(数据表),它们有与id相关的数据,每个表都有不同类型的数据。 我想从这些不同的表中按多个条件筛选id 我创建了如下查询,但这太慢了,大约3分钟。我查看了解释信息,但仍然找不到更好的方法。有人能找到更快的方法吗 质疑 编辑:谢谢你的评论。首先,我根据您的要求添加信息 为什么需要这个疑问 此查询旨在从“表单输入”标记接收post数据,用户从不同类别中选择选项以筛选ID。这就是为什么此查询包括本示例中未使用的表和数据 有这么多左联接的原因是每个“映射”表都有类别映射信息

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

我创建了如下查询,但这太慢了,大约3分钟。我查看了解释信息,但仍然找不到更好的方法。有人能找到更快的方法吗

质疑

编辑:谢谢你的评论。首先,我根据您的要求添加信息

为什么需要这个疑问

此查询旨在从“表单输入”标记接收post数据,用户从不同类别中选择选项以筛选ID。这就是为什么此查询包括本示例中未使用的表和数据

有这么多左联接的原因是每个“映射”表都有类别映射信息来过滤ID。等等,用户希望找到与“fea”、87、90和“ag”、98、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                   |                |
        +-------------+------------+------+-----+---------------------+----------------+
对不起,我解释得不好。我希望这次编辑能帮助你更好地理解。 编辑结束
这个查询已经有很多表了。删除任何未使用的表。这有什么原因吗

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根本不使用

一个很大的改进是在连接处使用多个条件,而不是获取一个庞大的集合,然后将条件放在末尾。我的意思是,如果您在加入集合的同时加入条件,您的集合将更小,响应时间也会更好:

 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
    ...

尝试以下方法:将您的左连接转换为一组存在的
子查询,并删除
分组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\u catg
    (cid)
  • jjtable_标签
    (tid,删除_标志)
  • jjtable\u映射
    和所有
    jjtable\u映射*
    (picid,delete\u标志,tid)

要优化查询,我们需要查看表和索引定义,以及每个表的行数。也许您的表定义不好。可能索引没有正确创建。也许你在你认为你有的专栏上没有索引。如果看不到表和索引定义,我们无法判断。我们还需要行计数,因为这会极大地影响查询优化。如果您知道如何进行
解释
或获得执行计划,请将结果也放在问题中。如果您没有索引,请尽快访问。基本上,您要加入的任何列(如
jjtm\u map\u per.tid
)都应该有索引。您能解释一下所有这些左连接应该实现什么功能吗?您甚至不使用(即聚合)它们生成的数据—实际上,您甚至可以像内部联接一样使用它们。谢谢您的回复。我为您的请求添加编辑数据。这是exelent!此查询将花费的时间从3分钟减少到0.03秒!我甚至不知道这句话。还有一个问题;根据我添加的ShowColumns信息,您认为我应该只在下面3列上添加索引吗。jjtable_标记:(delete_标志)jjtable_映射和所有jjtable_映射(delete_标志,tid)我对复合索引的观点是:如果满足条件所需的所有列(如“has tag id X且未标记为deleted”)都在索引中,服务器甚至不必查看基础表。它只需查看索引中预先排序的数据,就可以运行整个SELECT+连接。这大大加快了速度,但需要精心编制索引。我的答案中的索引建议是我认为它是最好的。您可以尝试不同的索引配置并使用EXPLAIN来查看MySQL是否使用它们以及它们如何影响查询性能。我想既然
jjtable\u-map
jjtable\u-map\u-ag
(等)基本上具有相同的结构:向
jjtable\u-map
添加另一列(假设
type
)并将其包含在索引
(type,picid,delete\u flag,tid)
。将所有“子表”及其各自的类型移到上面,然后使用
其中m.type='ag'和m.picid=jj.id m.delete_flag=0和t.tid in(98,99)和t.delete_flag=0
。这样可以降低数据库的复杂性并实现更好的规范化。表名中的
“\u ag'
(等)后缀实际上是数据,而不是结构。它们应该在表中。关于索引,我将尝试最佳配置,谢谢。为了消除子表问题,我编辑了您的答案部分。您的编辑被拒绝,因为您不应该以这种方式修改答案。但是我已经看到了,您是对的:您仍然会保留多个EXISTS子查询,现在只针对同一个表。正如我所说,统一表是为了改进通用数据库结构,即实现更好的数据库规范化。谢谢您的回复。我不知道我可以在JOIN上添加多个条件。我要试试这个!请告诉我进展如何谢谢。我添加了为什么需要编辑这些表。
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