2017-07-26 16 views
0

我有2個表。從這兩個表我試圖插入記錄到第三個表使用加入選擇查詢。然而,我發現選擇連接查詢不使用索引,並花了很多時間,因此插入非常緩慢。
我想在幾個帖子建議,但沒有利用創建多個索引。
MySQL with JOIN not using index
MySQL query with JOIN not using INDEX從表1選擇列加入表2,服用很長一段時間

這裏是我的表結構:

CREATE TABLE master_table (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, 
field1 VARCHAR(50) DEFAULT NULL, 
field2 VARCHAR(50) DEFAULT NULL, 
field3 VARCHAR(50) DEFAULT NULL, 
field4 VARCHAR(50) DEFAULT NULL, 
PRIMARY KEY (id), 
KEY mt_field1_index (field1) 
) ENGINE=INNODB DEFAULT CHARSET=utf8; 

CREATE TABLE child_table (
c_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, 
m_id BIGINT(20) UNSIGNED NOT NULL , 
group_id BIGINT(20) UNSIGNED NOT NULL , 
status ENUM('Status1','Status2','Status3') NOT NULL, 
job_id VARCHAR(50) DEFAULT NULL, 
PRIMARY KEY (c_id), 
UNIQUE KEY ct_mid_gid (m_id,group_id), 
KEY Index_ct_status (status), 
KEY index_ct_jobid (job_id), 
KEY index_ct_mid (m_id), 
KEY index_ct_cid_sts_tsk (group_id,status,job_id) 
) ENGINE=INNODB DEFAULT CHARSET=utf8; 

查詢:


SELECT m.id 
    , NULLIF(TRIM(m.field1),'') 
    FROM master_table m 
    JOIN child_table c 
    ON m.id = c.m_id 
WHERE c.group_id = 2 
    AND c.status = 'Status3' 
    AND c.job_id = 0 
ORDER 
    BY m.id 
LIMIT 0, 1000; 

解釋:


+-------+-------------+-------+------------+----------+------------------------------------------------------------------------------+-----------------+---------+--------------+-------+----------+------------------------------------------------+ 
| id | select_type | table | partitions | type |        possible_keys         |  key  | key_len |  ref  | rows | filtered |      Extra      | 
+-------+-------------+-------+------------+----------+------------------------------------------------------------------------------+-----------------+---------+--------------+-------+----------+------------------------------------------------+ 
|  1 | SIMPLE  | c | (NULL) | ref | ct_mid_gid,Index_ct_status,index_ct_jobid,index_ct_mid,index_ct_cid_sts_tsk | Index_ct_status |  1 | const  | 65689 |  0.00 | Using where; Using temporary; Using filesort | 
|  1 | SIMPLE  | m | (NULL) | eq_ref | PRIMARY                  | PRIMARY   |  8 | r_n_d.c.m_id |  1 | 100.00 | (NULL)           | 
+-------+-------------+-------+------------+----------+------------------------------------------------------------------------------+-----------------+---------+--------------+-------+----------+------------------------------------------------+ 

回答

1
WHERE c.group_id = 2 
    AND c.status = 'Status3' 
    AND c.job_id = 0 
ORDER BY c.m_id  -- Note the change 

需要

INDEX(group_id, status, job_id, -- in any order 
     m_id)      -- last 

你有什麼(單獨的索引)是相同。

爲了達到LIMIT該指數必須完全超過WHEREORDER BY。這可以防止計算所有行(LIMIT之前)和排序,然後才能執行LIMIT

所以,你得到4倍的速度提升:

  • 指數有效地獲取所需的行(來自c
  • 無需排序通(因爲ORDER BY提供它們按順序)
  • 該指數「覆蓋」(因此,沒有來回彈跳B樹索引和用於c數據B樹之間)
  • 獲取停止在1000

當你在這,考慮擺脫AUTO_INCREMENT的。折騰c_id和更改

PRIMARY KEY (c_id), 
UNIQUE KEY ct_mid_gid (m_id, group_id) 

- >

PRIMARY KEY(m_id, group_id) 

巧合的是,如果你做了這個,你KEY index_ct_cid_sts_tsk (group_id,status,job_id)會跌進了完美的指標。這是因爲PK是隱含上漲到任何輔助指標,但你需要m_idc_id。無論如何,我更喜歡明確。

當進行更改時,折騰任何冗餘索引。例如,是無用的,因爲它是另一個索引的開始。

+0

感謝您的詳細解答。只要我按順序使用'c.m_id'而不是m.id,就會停止使用filesort和temporary,並且使用索引和where添加建議的索引。 雖然我仍然想知道,如果我在where子句和當前條件一樣有m.field1 ='xyz'之類的東西,我應該使用什麼來按順序排列子句。我的意思是,何時使用c.m_id以及何時使用m.id – money

+0

而且如果我必須對僅存在於'master_table'中的列進行排序。類似於'order by m.field1,c.m_id' – money

+0

在某些情況下,優化器會注意到'c.m_id'與'm.id'相同,但我估計不會出現這種情況。 –

0

您是否製作在列指數where子句中使用? 通過在列上添加索引來檢查查詢。

,但如果添加索引,然後插入,更新和刪除表操作可能會慢千萬記住。

+0

KEY index_ct_cid_sts_tsk(group_id,status,job_id)已經存在。 – money

+0

@ money - close,但不夠充分;看到我的答案。 –

相關問題