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