2016-05-18 11 views
1

In Anbetracht der Tatsache, dass analisi_campo_free ist eine Tabelle mit etwa 1 Million Zeilen, gibt es eine leichtere Möglichkeit, diese Abfrage für mysql zu schreiben?mysql Abfrage mit mehreren Unterabfrage Optimierung

select distinct ID_ANALISI from analisi_campo_free 
    where 1=1 
    and ID_ANALISI IN (select ID_ANALISI from analisi_campo_free acf inner join campo_free cf on acf.id_campo_free = cf.id_campo_free where posizione = 1 and valore = '06/11/2015') 
    and ID_ANALISI IN (select ID_ANALISI from analisi_campo_free acf inner join campo_free cf on acf.id_campo_free = cf.id_campo_free where posizione = 3 AND valore='vvvvvv'); 

Dank


Die Abfrage

select distinct ID_ANALISI from analisi_campo_free 
where 1=1 
and ID_ANALISI IN (select ID_ANALISI from analisi_campo_free acf inner join campo_free cf on acf.id_campo_free = cf.id_campo_free where posizione = 1 and valore like 'irene%') 
and ID_ANALISI IN (select ID_ANALISI from analisi_campo_free acf inner join campo_free cf on acf.id_campo_free = cf.id_campo_free where posizione = 3 AND valore like 'antonio%'); 

benötigen etwa 2,3 Sekunden mit dieser

id select_type table partitions type possible_keys key key_len ref rows filtered Extra 
1 SIMPLE cf  index PRIMARY ID_LABORATORIO 4  6 16.67 Using where; Using index; Using temporary; Start temporary 
1 SIMPLE cf  index PRIMARY ID_LABORATORIO 4  6 16.67 Using where; Using index; Using join buffer (Block Nested Loop) 
1 SIMPLE acf  ALL ID_ANALISI,FK_ANALISI_CAMPO_FREE_CAMPO_FREE    1054163 11.11 Using where; Using join buffer (Block Nested Loop) 
1 SIMPLE acf  eq_ref ID_ANALISI,FK_ANALISI_CAMPO_FREE_CAMPO_FREE ID_ANALISI 5 elettroforesi.acf.ID_ANALISI,elettroforesi.cf.ID_CAMPO_FREE 1 11.11 Using where 
1 SIMPLE analisi_campo_free  ref ID_ANALISI ID_ANALISI 4 elettroforesi.acf.ID_ANALISI 1 100 Using index; End temporary 

Die Abfrage

erklären
SELECT acf.ID_ANALISI, COUNT(DISTINCT cf.posizione, acf.valore) AS matches 
FROM analisi_campo_free AS acf 
INNER JOIN campo_free AS cf ON acf.id_campo_free = cf.id_campo_free 
WHERE (posizione = 1 AND valore like 'irene%') 
    OR (posizione = 3 AND valore like 'antonio%') 
GROUP BY acf.ID_ANALISI 
HAVING matches = 2; 

erfordert etwa 1,3 Sekunden mit diesem erklären

id select_type table partitions type possible_keys key key_len ref rows filtered Extra 
1 SIMPLE cf  index PRIMARY ID_LABORATORIO 4  6 30.56 Using where; Using index; Using temporary; Using filesort 
1 SIMPLE acf  ALL ID_ANALISI,FK_ANALISI_CAMPO_FREE_CAMPO_FREE    1054163 20.99 Range checked for each record (index map: 0x6) 

Der Index sind:

Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment 
analisi_campo_free 0 PRIMARY 1 ID_ANALISI_CAMPO_FREE A 1054159    BTREE  
analisi_campo_free 0 ID_ANALISI 1 ID_ANALISI A 1049622    BTREE  
analisi_campo_free 0 ID_ANALISI 2 ID_CAMPO_FREE A 1049622    BTREE  
analisi_campo_free 1 FK_ANALISI_CAMPO_FREE_CAMPO_FREE 1 ID_CAMPO_FREE A 1    BTREE  


Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment 
campo_free 0 PRIMARY 1 ID_CAMPO_FREE A 6    BTREE  
campo_free 0 DESCRIZIONE 1 DESCRIZIONE A 6    BTREE  
campo_free 0 ID_LABORATORIO 1 ID_LABORATORIO A 1    BTREE  
campo_free 0 ID_LABORATORIO 2 POSIZIONE A 6    BTREE  
campo_free 0 ID_LABORATORIO 3 UTILIZZATO A 6   YES BTREE  

Ich habe nicht die Abfrage mit Paaren in Betracht gezogen, weil ich jetzt weiß, dass ich ein ähnliches benötigen. Am Ende werde ich vielleicht meine erste Abfrage verwenden, weil es einfacher ist, in querydsl zu übersetzen. Danke für Ihre Hilfe

+0

Leistungsfragen sollten 'EXPLAIN ANALYSE' und einige Informationen über Tabellengröße, Index, aktuelle Zeitleistung, Wunschzeit usw. enthalten.' Langsam' ist ein relativer Begriff und wir brauchen einen echten Vergleichswert. [** MySQL **] (http://dba.stackexchange.com/questions/15371/how-do-i-get-the-execution-plan-for-a-view) –

+0

@JuanCarlosOropeza so bist du mir sagen, dass Sie keine bessere Möglichkeit finden, die betreffende Frage zu schreiben, ohne die Werte von explain zu betrachten? * applaudiert sarkastisch * –

+0

@RahulSharma der wichtigste Teil der Optimierung ist der Index. So kannst du 80% deiner Zeit damit verbringen, 5% des Problems zu lösen. Aber ich arbeite lieber effizient. Sie können 'Lad 'Antwort überprüfen, ist eine großartige Lösung, aber wenn der Index nicht richtig eingestellt ist, wird immer noch schlechte Leistung haben. –

Antwort

1

könnten Sie verwenden:

SELECT ID_ANALISI 
FROM analisi_campo_free acf 
JOIN campo_free cf 
    ON acf.id_campo_free = cf.id_campo_free 
WHERE (posizione,valore) IN ((1,'06/11/2015'),(3,'vvvvvv')) 
GROUP BY ID_ANALSI 
HAVING SUM(posizione = 1 AND valore = '06/11/2015') > 0 
    AND SUM(posizione = 3 AND valore='vvvvvv') > 0; 
+0

Das wird nicht die gleichen Ergebnisse zurückgeben, wie es das äußere AND in ein OR geändert hat. – Uueerdo

+0

@Uueerdo Guter Punkt, behoben. – lad2025

1

Subqueries in WHERE-Klauseln sind in der Regel schlecht abschneiden in MySQL, vor allem korrelierte Unterabfragen. Dieser findet die zugehörigen campo_free Datensätze und zählt die eindeutigen Posizone, Valore-Paare, die den Kriterien entsprechen. Das HAVING versichert nur die ID_ANALISI, die beide in den Ergebnissen sind.

SELECT acf.ID_ANALISI, COUNT(DISTINCT cf.posizone, cf.valore) AS matches 
FROM analisi_campo_free AS acf 
INNER JOIN campo_free AS cf ON acf.id_campo_free = cf.id_campo_free 
WHERE (posizione = 1 AND valore = '06/11/2015') 
    OR (posizione = 3 AND valore='vvvvvv'); 
GROUP BY acf.ID_ANALISI 
HAVING matches = 2 
; 

Ohne die in COUNT verschieden; Wenn Posizone, Valore-Paare nicht für jeden id_campo_free-Wert eindeutig sind, könnte ID_ANALISI mit zwei (1, '6/11/2015') - oder (3, 'vvvvvv') - Treffern auch in den Endergebnissen enthalten sein.