2009-07-29 8 views
1

Kann jemand einen Hinweis auf diesen geben? :mysql query performance

Ich habe eine Tabelle, sagen wir tblA, wo ich ID1 und ID2 als Spalten und Index (ID1, ID2) habe. Ich möchte die ID1's auswählen, wo ID2's zu mehreren Sets gehören. Deshalb würde ich sagen will

select id1 from tblA 
where id2 in (val1,val2,val3 ...) 
union 
select id1 from tblA 
where id2 in (val4,val2,val3 ...) 
union 
(...)* 

Lassen Sie uns sagen, dass wir in der Tabelle A haben die folgenden:

(1,1) 
(1,2) 
(1,3) 
(1,4) 
(1,5) 
(2,1) 
(2,2) 
(2,3) 

Jetzt möchte ich alle id1 s, die id2 in (3,4) haben.

Also was ich bekommen möchte ist id1 = 1.

2 sollte nicht angezeigt werden, denn obwohl wir eine Beziehung haben (2,3) haben wir (2,4) nicht.

Haben Sie Ideen, wie Sie diese Abfrage durchführen? Ich denke, der obige Weg hat ein Problem mit der Leistung, wenn der (...) zu viel wächst !? Vielen Dank.

begrüßt

+0

ok, also werde ich versuchen, es mit einem Beispiel zu erklären. Ich habe versucht, beide Ihre Fragen, aber es ist nicht das, was ich will. Nehmen wir an, wir haben in Tabelle A folgendes: (1,1), (1,2), (1,3), (1,4), (1,5), (2,1), (2, 2), (2,3). Jetzt möchte ich alle id1s, die id2 in (3,4) haben. Also, was ich will, bekommen seine id1s = "1". "2" sollte nicht Ursache sein, obwohl wir eine Beziehung (2,3) haben, die wir nicht (2,4) haben. Habe ich mich klar ausgedrückt? Das ist irgendwie schwer zu erklären ... danke trotzdem –

+0

Nur aus Neugier, warum? :) Es gibt ein paar Antworten, die aussehen, als würden sie gut funktionieren. Welcher würde am meisten Sinn machen, und wenn etwas anderes für Sie besser funktionieren könnte, kann nicht ohne das warum beantwortet werden? Wenn sich die Dinge nicht oft ändern, können Sie Ihre Listen mit vielen Abfragen füllen und sie dann aktualisieren. Dann wird Ihre Antwort sofort sein. Das Erstellen einer einfachen temporären Tabelle mit nur der ID1 und einem booleschen Wert kann Ihnen helfen, jeden Satz zu filtern (d. H. Diejenigen zu finden, die in jedem Durchgang übereinstimmen). – TheJacobTaylor

Antwort

0

Die Gewerkschaft werde Ihre Leistung töten. Verwenden Sie etwas wie folgt:

select id1 from tblA where id2 in (val1,val2,val3 ...) or id2 in (val4,val2,val3) 
+0

Meinten Sie, Sie möchten alle ID1-Werte, für die ID2 in jeder dieser Untergruppen vorhanden ist (dies scheint durch Ihre Formulierung angezeigt zu sein, aber die Beispielabfrage wird nicht als solche ausgeführt). Wenn dies der Fall ist, müssen Sie nur die 'oder' in der where-Klausel in 'and' ändern. –

+0

Bitte überprüfen Sie meinen Kommentar oben, es war nicht das, was ich meinte –

0

Können Sie alle Sätze in einem großen Satz kombinieren?

Wenn die Reihenfolge nicht wichtig ist, scheint dies der schnellste Weg zu sein.

0

Zunächst erinnern, dass

select id1 from tblA where id2 in (val1, val2, val3) union 
select id1 from tblA where id2 in (val4, val5, val6) 

sollte das gleiche Ergebnis wie

select id1 from tblA where id2 in (val1, val2, val3, val4, val5, val6) 

geben, so können Sie vielleicht die Effizienz verbessern, indem eine einzelne Abfrage zu formulieren, anstatt eine Vereinigung mit.

Zweitens (und unabhängig von den oben genannten) sollten Sie einen Index auf ID2 zu tblA hinzufügen. Ohne sie werden die id2-Werte zufällig sowohl durch den vorhandenen Index als auch durch die Tabellendaten verteilt, so dass der Optimierer keine andere Wahl hat, als einen linearen Scan durchzuführen - des Index, wenn Sie Glück haben.

0

Aber alle diese Abfragen geben beide IDs von Spalte ID1 zurück! Ich denke, Robert meinte, dass als Folge er nur „1“ aus der Spalte id1 will:

id1 id2 
    1 | 1 
    1 | 2 
    1 | 3 
    1 | 4 --> id1s that have id2 with 3 and 4 
    1 | 5 
    2 | 1 
    2 | 2 
    2 | 3 

Da id1 = 2 nicht über 3 und 4 kein Ergebnis sein sollte.

Bitte korrigieren Sie mich, wenn ich missverstanden ... Ich habe versucht, eine Aussage zu machen, aber ich konnte nicht nur die ID1 = 1 zurück, aber ich bin auch sehr daran interessiert, eine effiziente Lösung für diese!

0

Sie müssen einen separaten Index für die Spalte 'id2' erstellen, da der kombinierte Index on (ID1, ID2) nicht verwendet wird, wenn nur nach ID2 gesucht wird.

Diese Abfrage tut, was Sie

erwähnt
SELECT id1 FROM tblA WHERE id2 IN (?,?,?,?) 
GROUP BY id1 HAVING COUNT(id2)=4 

Hinweis: Sie müssen in HAVING-Klausel erwähnt auf die Anzahl der Werte in der IN-Klausel des COUNT (ID2) Zustand einzustellen. Hier habe ich vier '?' Um vier Werte zu repräsentieren, habe ich COUNT (id2) = 4 geschrieben.

Für das Szenario, die Sie im Kommentar erwähnt, wird Abfrage aussehen wie folgt

SELECT id1 FROM tblA WHERE id2 IN (3,4) 
GROUP BY id1 HAVING COUNT(id2)=2 
1

Sie sollten eine temporäre Tabelle wie folgt erstellen:

CREATE TABLE temp (id INT NOT NULL PRIMARY KEY) ENGINE MEMORY; 

, füllen Sie es Sie mit Werten suchen für (2 und 3 in Ihrem Beispiel):

INSERT 
INTO temp 
VALUES (3), (4) 

und geben Sie diese Abfrage:

SELECT ad.id1 
FROM (
     SELECT DISTINCT id1 
     FROM a 
     ) ad 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM temp 
     WHERE NOT EXISTS 
       (
       SELECT NULL 
       FROM a 
       WHERE a.id1 = ad.id1 
         AND a.id2 = temp.id 
       ) 
     ) 

Sie sollten einen zusammengesetzten Index für (id1, id2) dafür erstellen zu arbeiten.

Für jeden id1 wird diese Sonde jeden id2 gegen temp höchstens einmal und wird, sobald die ersten id2 abwesend in temp gefunden wird für jeden id1 false zurück.

Hier ist der Plan für die Abfrage:

1, 'PRIMARY', '<derived2>', 'ALL', '', '', '', '', 2, 'Using where' 
3, 'DEPENDENT SUBQUERY', 'temp', 'ALL', '', '', '', '', 2, 'Using where' 
4, 'DEPENDENT SUBQUERY', 'a', 'eq_ref', 'PRIMARY', 'PRIMARY', '8', 'ad.id1,test.temp.id', 1, 'Using index' 
2, 'DERIVED', 'a', 'range', '', 'PRIMARY', '4', '', 3, 'Using index for group-by' 

, keine temporary, keine filesort.