2016-07-13 6 views
0

Ich habe die folgende Abfrage, die paar Ansichten 'golddedRunQueries' und 'currentGoldMarkings' verweist. Mein Problem scheint aus der Sicht zu stammen, die in der Unterabfrage - currentGoldMarkings - aufgeführt ist. Während der Ausführung materialisiert MySQL zuerst diese Unterabfrage und implementiert dann die Where-Klauseln von 'queryCode' und 'runId', was zu einer Ausführungszeit von mehr als einer Stunde führt, da die View auf Tabellen mit Millionen von Datenzeilen verweist. Meine Frage ist, wie kann ich diese beiden Bedingungen in der Unterabfrage erzwingen, bevor es sich materialisiert.Bedingungen von äußeren Abfrage auf eine materialisierte Unterabfrage geben

SELECT goldedRunQueries.queryCode, goldedRunQueries.runId 
    FROM goldedRunQueries 
    LEFT OUTER JOIN 
     (SELECT measuredRunId, queryCode, COUNT(resultId) as c 
      FROM currentGoldMarkings 
      GROUP BY measuredRunId, queryCode 
    ) AS accuracy ON accuracy.measuredRunId = goldedRunQueries.runId 
     AND accuracy.queryCode = goldedRunQueries.queryCode 
    WHERE goldedRunQueries.queryCode IN ('CH001', 'CH002', 'CH003') 
     and goldedRunQueries.runid = 5000 
    ORDER BY goldedRunQueries.runId DESC, goldedRunQueries.queryCode; 

Hier sind die zwei Ansichten. Beide werden auch in einem Stand-Alone-Modus verwendet und daher ist es nicht möglich, Klauseln in sie zu integrieren.

CREATE VIEW currentGoldMarkings 
AS 
SELECT result.resultId, result.runId AS measuredRunId, result.documentId, 
     result.queryCode, result.queryValue AS measuredValue, 
     gold.queryValue AS goldValue, 
     CASE result.queryValue WHEN gold.queryValue THEN 1 ELSE 0 END AS correct 
    FROM results AS result 
    INNER JOIN gold ON gold.documentId = result.documentId 
     AND gold.queryCode = result.queryCode 
    WHERE gold.isCurrent = 1 

CREATE VIEW goldedRunQueries 
AS 
SELECT runId, queryCode 
    FROM runQueries 
    WHERE EXISTS 
     (SELECT 1 AS Expr1 
      FROM runs 
      WHERE (runId = runQueries.runId) 
       AND (isManual = 0) 
    ) 
     AND EXISTS 
     (SELECT 1 AS Expr1 
      FROM results 
      WHERE (runId = runQueries.runId) 
       AND (queryCode = runQueries.queryCode) 
       AND EXISTS 
       (SELECT 1 AS Expr1 
        FROM gold 
        WHERE (documentId = results.documentId) 
         AND (queryCode = results.queryCode) 
      ) 
    ) 

Hinweis: Die obige Abfrage spiegelt nur einen Teil meiner tatsächlichen Abfrage wider. Es gibt 3 andere linke äußere Verbindungen, die der obigen Unterabfrage ähnlich sind, was das Problem viel schlimmer macht.

EDIT: Wie bereits angedeutet, hier ist die Struktur und einige Beispieldaten für die Tabellen

CREATE TABLE `results`(
`resultId` int auto_increment NOT NULL, 
`runId` int NOT NULL, 
`documentId` int NOT NULL, 
`queryCode` char(5) NOT NULL, 
`queryValue` char(1) NOT NULL, 
`comment` varchar(255) NULL, 
CONSTRAINT `PK_results` PRIMARY KEY 
(
`resultId` 
) 
); 


insert into results values (100, 242300, 'AC001', 'I', NULL) 
insert into results values (100, 242300, 'AC001', 'S', NULL) 
insert into results values (150, 242301, 'AC005', 'I', 'abc') 
insert into results values (100, 242300, 'AC001', 'I', NULL) 
insert into results values (109, 242301, 'PQ001', 'S', 'zzz') 
insert into results values (400, 242400, 'DD006', 'I', NULL) 



CREATE TABLE `gold`(
`goldId` int auto_increment NOT NULL, 
`runDate` datetime NOT NULL, 
`documentId` int NOT NULL, 
`queryCode` char(5) NOT NULL, 
`queryValue` char(1) NOT NULL, 
`comment` varchar(255) NULL, 
`isCurrent` tinyint(1) NOT NULL DEFAULT 0, 
CONSTRAINT `PK_gold` PRIMARY KEY 
(
`goldId` 
) 
); 



insert into gold values ('2015-02-20 00:00:00', 138904, 'CH001', 'N', NULL, 1) 
insert into gold values ('2015-05-20 00:00:00', 138904, 'CH001', 'N', 'aaa', 1) 
insert into gold values ('2016-02-20 00:00:00', 138905, 'CH002', 'N', NULL, 0) 
insert into gold values ('2015-12-12 00:00:00', 138804, 'CH001', 'N', 'zzzz', 1) 



CREATE TABLE `runQueries`(
`runId` int NOT NULL, 
`queryCode` char(5) NOT NULL, 
CONSTRAINT `PK_runQueries` PRIMARY KEY 
(
`runId`, 
`queryCode` 
) 
); 


insert into runQueries values (100, 'AC001') 
insert into runQueries values (109, 'PQ001') 
insert into runQueries values (400, 'DD006') 



CREATE TABLE `runs`(
`runId` int auto_increment NOT NULL, 
`runName` varchar(63) NOT NULL, 
`isManual` tinyint(1) NOT NULL, 
`runDate` datetime NOT NULL, 
`comment` varchar(1023) NULL, 
`folderName` varchar(63) NULL, 
`documentSetId` int NOT NULL, 
`pipelineVersion` varchar(50) NULL, 
`isArchived` tinyint(1) NOT NULL DEFAULT 0, 
`pipeline` varchar(50) NULL, 
CONSTRAINT `PK_runs` PRIMARY KEY 
(
`runId` 
) 
); 


insert into runs values ('test1', 0, '2015-08-04 06:30:46.000000', 'zzzz', '2015-08-04_103046', 2, '2015-08-03', 0, NULL) 
insert into runs values ('test2', 1, '2015-12-04 12:30:46.000000', 'zzzz', '2015-08-04_103046', 2, '2015-08-03', 0, NULL) 
insert into runs values ('test3', 1, '2015-06-24 10:56:46.000000', 'zzzz', '2015-08-04_103046', 2, '2015-08-03', 0, NULL) 
insert into runs values ('test4', 1, '2016-05-04 11:30:46.000000', 'zzzz', '2015-08-04_103046', 2, '2015-08-03', 0, NULL) 
+0

Wenn Sie möchten, in Betracht ziehen, richtige CREATE und INSERT-Anweisungen UND ein gewünschtes Ergebnis – Strawberry

+0

@Strawberry Es tut mir leid, aber ich habe Ihren Kommentar nicht ganz verstanden. CREATE- und INSERT-Anweisungen für welche Objekte? – PratikGandhi

+0

Nun, die Tabellen, die verwendet werden, um "golddedRunQueries" und "currentGoldMarkings" zu konstruieren, scheinen mir die offensichtlichen Kandidaten zu sein - also 'results',' gold', 'runs' und' runQueries' – Strawberry

Antwort

1

Lassen Sie uns zuerst versuchen, die Leistung über Indizes zu verbessern:

Ergebnisse: INDEX (RunID, queryCode) - in beliebiger Reihenfolge Gold: INDEX (DocumentID, query_code, IsCurrent) - in dieser Reihenfolge

Danach aktualisieren Sie die CREATE TABLEs in der Frage und fügen Sie die Ausgabe von:

EXPLAIN EXTENDED SELECT ...; 
SHOW WARNINGS; 

In welcher Version laufen Sie? Sie haben effektiv FROM (SELECT ...) JOIN (SELECT ...). Vor 5.6 hatte keine Unterabfrage einen Index; Mit 5.6 wird ein Index on the fly generiert.

Es ist eine Schande, dass die Abfrage auf diese Weise erstellt wird, da Sie wissen, welche zu verwenden: and goldedRunQueries.runid = 5000.

Bottom Line: fügen Sie die Indizes hinzu; Upgrade auf 5,6 oder 5,7; Wenn das nicht genug ist, dann überdenken Sie die Verwendung von VIEWs.

+0

Nun, ich konvertierte die Ansichten in Stored Procedures und bin nun in der Lage, die Bedingungen über Parameter zu übergeben. @RickJames Eine kurze Frage über die Indexreihenfolge, die Sie für die Gold-Tabelle angegeben haben - warum haben Sie nicht "isCurrent" als erste Spalte, da sie dort für eine der Ansichten verwendet wird? – PratikGandhi

+0

Die letzte Unterabfrage hat nicht 'iscurrent'; die ersten 2 Spalten sind vorteilhaft. –

Verwandte Themen