2017-07-26 2 views
0

Ich habe 2 Tabellen. Von diesen zwei Tabellen versuche ich, Datensätze in eine dritte Tabelle einzufügen, die eine Auswahlabfrage mit Join verwendet. Allerdings habe ich festgestellt, dass Abfrage mit Join keine Indizes verwenden und viel Zeit braucht, daher ist die Einfügung sehr langsam.
Ich habe versucht, mehrere Indizes zu erstellen, wie in einigen Posts vorgeschlagen, aber nicht in Anspruch genommen.
MySQL with JOIN not using index
MySQL query with JOIN not using INDEXWählen Sie Spalten aus Tabelle1 Join Tabelle2, sehr lange dauern

Hier sind meine Tabellen Struktur:

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; 

Abfrage:


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; 

Erklären:


+-------+-------------+-------+------------+----------+------------------------------------------------------------------------------+-----------------+---------+--------------+-------+----------+------------------------------------------------+ 
| 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)           | 
+-------+-------------+-------+------------+----------+------------------------------------------------------------------------------+-----------------+---------+--------------+-------+----------+------------------------------------------------+ 

Antwort

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

Needs

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

Was haben Sie (getrennte Indizes) ist nicht gleich.

Um an die LIMIT zu gelangen, muss der Index die WHERE und ORDER BY vollständig hinter sich lassen. Dies verhindert, dass alle Zeilen (vor der LIMIT) und die Sortierung berechnet werden und erst dann die LIMIT.

So erhalten Sie 4 speedups:

  • Index die gewünschten Zeilen effizient zu holen (von c)
  • Keine Notwendigkeit für eine Art Pass (seit ORDER BY sie um liefert)
  • Der Index wird „abdecken“ (daher kein Prellen hin und her zwischen Index und Daten BTree BTree für c)
  • Erhalten bei 1000.
zu stoppen

Während Sie dabei sind, ziehen Sie in Betracht, die AUTO_INCREMENT loszuwerden. Wirf c_id und

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

ändern ->

PRIMARY KEY(m_id, group_id) 

Zufälligerweise, wenn Sie dies getan hatte, Ihre KEY index_ct_cid_sts_tsk (group_id,status,job_id) hätte in den perfekten Index gestolpert. Dies liegt daran, dass der PK implizit an jeden sekundären Index angeheftet wird, aber Sie brauchen m_id, nichtc_id. Wie auch immer, ich ziehe es vor, explizit zu sein.

Und wenn Sie Änderungen vornehmen, werfen Sie alle redundanten Indizes. Zum Beispiel ist nutzlos, da es der Anfang eines anderen Indexes ist.

+0

Danke für die ausführliche Antwort. Sobald ich 'c.m_id' anstelle von m.id in der order by-Klausel verwendet habe, hat es die Verwendung von filesort und temporary gestoppt und beim Hinzufügen des vorgeschlagenen Indexes hat es begonnen, index with where zu verwenden. Obwohl ich mich immer noch frage, ob ich etwas wie m.field1 = 'xyz' in where-Klausel zusammen mit der aktuellen Bedingung hatte, was hätte ich für order by clause verwenden sollen. Ich meine, wann c.m_id zu verwenden und wann m.id – money

+0

Und wenn ich nach der Spalte sortieren muss, die nur in 'master_table' existiert. So etwas wie 'order by m.field1, c.m_id' – money

+0

In einigen Situationen würde der Optimizer bemerken, dass' c.m_id' dasselbe ist wie 'm.id', aber in diesem Fall nicht. –

0

Haben Sie einen Index für die in where-Klausel verwendeten Spalten erstellt? Abfrage durch Hinzufügen von Index für Spalten prüfen.

aber denken Sie daran, wenn Sie Index hinzufügen dann Einfügen, Aktualisieren und Löschen der Operation auf Tabelle kann langsam werden.

+0

KEY index_ct_cid_sts_tsk (group_id, status, job_id), schon da. – money

+0

@money - nah, aber nicht ganz ausreichend; Sieh meine Antwort. –

Verwandte Themen