[英]Very slow mysql query: left join multiple table and where clause for each table
我有一個基本表(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。 這就是為什么此查詢包含此示例中未使用的表和數據的原因。
左聯接之所以這么多,是因為每個“映射”表都有類別映射信息以過濾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 | |
+-------------+------------+------+-----+---------------------+----------------+
對不起,我的解釋不好。 希望此編輯有助於您更好地理解。 編輯結束
一個大的改進是在聯接上使用多個條件,而不是獲得一個巨大的集合,然后將條件放在最后。 我的意思是,如果您同時添加條件,則加入集合的條件會更小,響應時間會更好:
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
...
嘗試以下操作:將您的左聯接轉換為一堆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)
該查詢已經有很多表。 刪除任何未使用的表。 有什么理由加入嗎?
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。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.