2016-11-15 2 views
1

Wir sind genervt von dem Symptom unten. Wir freuen uns über jeden Hinweis von Ihnen über die Ursache und die Art und Weise, wie Sie diese beheben können.Eine langsame Abfrage in Oracle (läuft in SQL Server schnell) (eine korrelierte Unterabfrage)

Ich führe die einfache Abfrage unten und es dauerte 3.800 Sekunden für Oracle DB, um das Ergebnis zurückzugeben, während die gleiche Abfrage in ein paar Sekunden in einer SQL Server-Datenbank, die die gleichen Tabellen hat abgeschlossen. (Es wird als Datamart verwendet).

Abfrage:

select 
T_X.Col1 
,(select count(1) from T_X where T_X.colX = T_Y.colY) as cnt1 
from T_Y 

Aufzeichnungen zählen:

t_x: 96.536

T_Y: 129.359

Weitere Informationen:

-ColY ist der Primärschlüssel von T_Y und es gibt keinen Index für ColXin in beiden der beiden Umgebungen.

-Oracle 11.1 (lief die Abfrage SQL Developer verwenden)

-SQL Server 2008 (lief die Abfrage mit SSMS) zwischen den beiden Umgebung

-Nr große Unterschiede von Hardware-Spezifikationen.

-Die obige Abfrage ist ein Teil des größeren. Wir haben es vereinfacht und festgestellt, dass der Teil der Engpass war.

Wir würden uns über Ihren Ratschlag freuen!

Zusätzliche Informationen (der Zweck der Abfrage)

Die Abfrage oben ist ein Teil der unter Abfrage. Unser Zweck besteht darin, Datensätze (die Anzahl von) in T_Y herauszufinden, die keine Korrespondenzaufzeichnungen in anderen Tabellen haben (T_A, T_B, T_C, T_D, T_E, T_X).

select   
    count(1)   
from    
    (select 
    T_Y.ColA 
    ,T_Y.ColG 
    ,T_Y.ColH 
    ,(select count(1) from T_A A where A.ColA = T_Y.ColY) as cnt1 
    ,(select count(1) from T_B B where B.ColB = T_Y.ColY) as cnt2 
    ,(select count(1) from T_X where T_X.ColX = T_Y.ColY) as cnt3 
    ,(select count(1) from T_C C where C.ColC = T_Y.ColY) as cnt4 
    ,(select count(1) from T_D D where D.ColD = T_Y.ColY) as cnt5 
    ,(select count(1) from T_E E where E.ColE = T_Y.ColY) as cnt6 
    from T_Y 
)XXX 
where 1=1 
    and XXX.ColH in ('X') 
    and XXX.cnt1 = 0 
    and XXX.cnt2 = 0 
    and XXX.cnt3 = 0 
    and XXX.cnt4 = 0 
    and XXX.cnt5 = 0 
    and XXX.cnt6 = 0 
;   

Ausführungsplan - Oracle (für die ursprüngliche Abfrage) (Execute-Plan Erklären)

"Optimizer" "Cost" "Cardinality" "Bytes" "Partition Start" "Partition Stop" "Partition Id" "ACCESS PREDICATES" "FILTER PREDICATES" 
"SELECT STATEMENT" "ALL_ROWS" "121" "129359" "776154" "" "" "" "" "" 
"SORT(AGGREGATE)" "" "" "1" "6" "" "" "" "" "" 
"TABLE ACCESS(FULL) XXXXX.T_X" "ANALYZED" "6616" "2" "12" "" "" "" "" ""T_X"."ColX"=:B1" 
"INDEX(FAST FULL SCAN) XXXXX.T_Y_0" "ANALYZED" "121" "129359" "776154" "" "" "" "" "" 

Ausführungsplan - SQL Server (für die ursprüngliche Abfrage)

Linie 7 gibt an, dass SQL Server Clustered Index Scan anstelle von Table Scan verwendet, obwohl der Clustered-Index ColumnY nicht enthält. Könnte jemand erklären, was das bedeutet? Kann ich Oracle dazu zwingen, den ähnlichen Ausführungsplan mit einer Hinweisklausel oder irgendetwas zu verwenden?

|--Compute Scalar(DEFINE:([Expr1008]=CASE WHEN [Expr1006] IS NULL THEN (0) ELSE [Expr1006] END)) 
     |--Parallelism(Gather Streams) 
      |--Hash Match(Right Outer Join, HASH:([DB_X].[dbo].[T_X].[ColX])=([DB_X].[dbo].[T_Y].[ColY]), RESIDUAL:([DB_X].[dbo].[T_X].[ColX]=[DB_X].[dbo].[T_Y].[ColY])) 
       |--Compute Scalar(DEFINE:([Expr1006]=CONVERT_IMPLICIT(int,[Expr1013],0))) 
       | |--Hash Match(Aggregate, HASH:([DB_X].[dbo].[T_X].[ColX]), RESIDUAL:([DB_X].[dbo].[T_X].[ColX] = [DB_X].[dbo].[T_X].[ColX]) DEFINE:([Expr1013]=COUNT(*))) 
       |   |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([DB_X].[dbo].[T_X].[ColX])) 
       |    |--Clustered Index Scan(OBJECT:([DB_X].[dbo].[T_X].[PK_T_X])) 
       |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([DB_X].[dbo].[T_Y].[ColY])) 
         |--Clustered Index Scan(OBJECT:([DB_X].[dbo].[T_Y].[PK_T_Y])) 
+0

Ihre Anfrage ist verwirrend. Beschreibe in Worten, was deine Intention ist - das hilft manchmal. –

+0

Korrektur: colY ist der Primärschlüssel von T_Y. – yobioo

+0

Bitte buchen Sie die Ausführungspläne für die Abfragen in beiden Datenbanken. – sstan

Antwort

0

Unser Ziel ist es, herauszufinden (die Anzahl der) Aufzeichnungen in T_Y, die nicht Korrespondent hat Datensätze in anderen Tabellen (T_A, T_B, T_C, T_D, T_E, t_x).

, die besser ausgedrückt werden würde:

select   
    count(*)   
from    
    T_Y 
where ColH in ('X') and 
     not exists (select null from T_A A where A.ColA = T_Y.ColY) and 
     not exists (select null from T_B B where B.ColB = T_Y.ColY) and 
     not exists (select null from T_X where T_X.ColX = T_Y.ColY) and 
     not exists (select null from T_C C where C.ColC = T_Y.ColY) and 
     not exists (select null from T_D D where D.ColD = T_Y.ColY) and 
     not exists (select null from T_E E where E.ColE = T_Y.ColY); 
+0

David, vielen Dank für die Lösung! Ihre SQL hat die Ergebnisse in nur 2 Minuten (mit gelöschtem Cache) abgerufen. – yobioo

0

Sie benötigen einen Index für t_x(colX). Ich vermute, dass dieser Index auf SQL Server existiert.

Diese Version könnte schneller auf jeder Maschine:

select t_x.colX, count(1) 
from T_X 
group by t_x.colX; 

Es ist nicht genau das gleiche, aber es könnte sein, was Sie wirklich wollen.

+0

Danke für den Kommentar! Wie ich den ursprünglichen Beitrag korrigierte, war colY der Primärschlüssel von T_Y. Die beiden Umgebungen teilen jedoch die gleichen Bedingungen für die Schlüssel und die Indizes. – yobioo

+0

Ich denke, das Hinzufügen eines Indexes funktioniert gut, aber wir dürfen keine Änderungen an den Definitionen der Objekte vornehmen, da die DB ein Teil der Paket-Software ist. Ich dachte, wenn es in SQL Server ohne Änderung der Definitionen gut funktionierte, warum nicht in Oracle. – yobioo

+0

Dies könnte ein Fall sein, in dem SQL Server die Abfrage besser als Oracle optimiert, obwohl das mich überraschen würde. Oracle ist normalerweise ziemlich gut mit dieser Art von Abfrage. –

Verwandte Themen