2017-01-11 3 views
-1

Die Abfrage, die abgestimmt werden soll, ist die folgende.Was ist die andere Art der Abstimmung der inneren Ansicht?

Und die Eingabe auf die Abfrage year_Month='201507'

SELECT A.account_number, 
     A.market, 
     A.security_type, 
     A.total_market_value, 
     A.max_event_Date, 
     -- first inner Query 
(SELECT COUNT(*) 
     FROM MIGC_ACCOUNT_STATEMENT acctStmt 
     WHERE acctStmt.account_number =A.account_number 
     AND acctStmt.market    =A.market 
     AND acctStmt.security_type  =A.security_type 
     AND acctStmt.year_Month   =A.year_Month 
     AND acctStmt.ACCOUNT_EVENT_DATE = A.max_event_Date 
    ) AS isincount, 
     -- second inner Query 
     (SELECT COUNT(COUNT(*)) 
     FROM MIGC_ACCOUNT_STATEMENT acctStmt 
     WHERE acctStmt.account_number =A.account_number 
     AND acctStmt.market   =A.market 
     AND((acctStmt.security_type =A.security_type) 
     OR (acctStmt.security_type IS NULL)) 
     AND acctStmt.year_Month  =A.year_Month 
     GROUP BY acctStmt.ACCOUNT_EVENT_DATE 
    ) AS totalcount, 
     -- 3rd inner Query 
     (SELECT COUNT(*) 
     FROM MIGC_ACCOUNT_STATEMENT acctStmt 
     WHERE acctStmt.account_number =A.account_number 
     AND acctStmt.market    =A.market 
     AND acctStmt.security_type  =A.security_type 
     AND acctStmt.year_Month   =A.year_Month 
     AND acctStmt.ACCOUNT_EVENT_DATE = A.max_event_Date 
     AND acctStmt.market_value  = 0 
    ) AS zero_market_value, 
    -- 4th inner Query 
     (SELECT SUM(acctStmt.market_value) 
     FROM MIGC_ACCOUNT_STATEMENT acctStmt 
     WHERE acctStmt.account_number =A.account_number 
     AND acctStmt.market    =A.market 
     AND acctStmt.security_type  =A.security_type 
     AND acctStmt.ACCOUNT_EVENT_DATE =A.max_event_Date 
     AND acctStmt.year_Month   =A.year_Month 
     GROUP BY acctStmt.account_number, 
     acctStmt.security_type, 
     acctStmt.market 
    ) AS mon_end_value 
    FROM 
--inner view 
     (SELECT account_number, 
     market, 
     security_type, 
     SUM(market_value)  AS total_market_value, 
     MAX(ACCOUNT_EVENT_DATE) AS max_event_Date, 
     year_Month 
     FROM MIGC_ACCOUNT_STATEMENT 
     WHERE year_Month ='201507' 
     AND security_Type IS NOT NULL 
     GROUP BY account_number, 
     market, 
     security_type, 
     year_Month 
    ) A 

Meine Tabellenstruktur ist unter

CREATE TABLE MIGC_ACCOUNT_STATEMENT" 
    (
    "ID"   VARCHAR2(15 CHAR) NOT NULL ENABLE, 
    "REQUEST_ID" VARCHAR2(100 CHAR), 
    "REQUEST_DATE" TIMESTAMP (6), 
    "PRODUCT_GROUP"  VARCHAR2(50 CHAR), 
    "SOURCE_SYSTEM"  VARCHAR2(3 CHAR), 
    "PROCESSED_BY_SITE" VARCHAR2(50 CHAR), 
    "ACCOUNT_EVENT_DATE" DATE, 
    "ACCOUNT_NUMBER" VARCHAR2(50 CHAR), 
    "SECURITY_ID" VARCHAR2(50 CHAR), 
    "SECURITY_TYPE" VARCHAR2(100 CHAR), 
    "SECURITY_NAME" VARCHAR2(200 CHAR), 
    "SECURITY_PRICE" NUMBER, 
    "SECURITY_PRICE_DATE" DATE, 
    "QUANTITY"    NUMBER, 
    "MARKET_VALUE_CURRENCY" VARCHAR2(5 CHAR), 
    "MARKET"    VARCHAR2(100 CHAR), 
    "MARKET_VALUE"   NUMBER, 
    "SECURITY_ID_TYPE"  VARCHAR2(50 CHAR), 
    "LOB_ID"    VARCHAR2(20 CHAR), 
    "YEAR_MONTH"   NUMBER, 
    "BATCH_NUMBER"   NUMBER NOT NULL ENABLE, 
    "CUSTOMER_ID"   VARCHAR2(50 CHAR)  
) 

und Id Primärschlüssel ist. Ich habe die Abfragekosten überprüft und es ist sehr hoch.

+3

Bitte stellen Sie den EXPLAIN-Plan dieser Abfrage und Indizes auf Ihre Tabelle – Aleksej

+0

ID-Spalte ist indiziert. – Sunil

+1

Und ist ID die einzige indizierte Spalte? – Aleksej

Antwort

1

Dies ist zu lang für einen Kommentar.

Zuerst sollten Sie alle für die Korrelationen verwendeten Spalten indizieren - einen Index mit zusammengesetzten Schlüsseln. Also: MIGC_ACCOUNT_STATEMENT(account_number, acctStmt.market, security_type, year_Month, ACCOUNT_EVENT_DAT) ist der optimale Index für den ersten.

Zweitens, verwenden Sie nicht COUNT(COUNT(*)). Meine Vermutung ist, dass selbst Oracle-Kenner, die das Konstrukt wirklich verstehen, COUNT(DISTINCT acctStmt.ACCOUNT_EVENT_DATE) noch klarer finden. (Anmerkung: Diese sind nicht genau gleich, weil Ihre Version NULL zählt Ich vermute, dass dies nicht geschieht..)

+0

Wie können Sie vorschlagen, Indizes hinzuzufügen, ohne die Join-Kardinalität zu kennen oder einen Ausführungsplan zu sehen? – BobC

+0

@BobC. . . Die notwendigen Indizes erscheinen mir aufgrund der ausgeführten Abfrage offensichtlich. –

0

glaube ich Ihnen die mehrere Tabellen Lookups der gleichen Tabelle unter Verwendung von bedingten analytischen vermeiden können Funktionen, etwa so:

SELECT account_number, 
     market, 
     security_type, 
     SUM(CASE WHEN a.security_type is not NULL THEN market_value END) AS total_market_value, 
     isincount, 
     totalcount, 
     zero_market_value, 
     mon_end_value 
FROM (SELECT a.account_number, 
       a.market, 
       a.security_type, 
       a.max_event_date, 
       COUNT(CASE WHEN a.security_type is not NULL 
           AND a.account_event_date = max_event_date THEN ID END) 
       OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS isincount, 
       COUNT(DISTINCT NVL(a.account_event_date, DATE '1800-01-01')) 
       OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS totalcount, 
       COUNT(CASE WHEN a.security_type is not NULL 
           AND a.account_event_date = max_event_date 
           AND a.market_value = 0 THEN ID END) 
       OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS zero_market_value, 
       SUM(CASE WHEN a.security_type is not NULL 
          AND a.account_event_date = max_event_date THEN a.market_value END) 
       OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS mon_end_value 
     FROM --inner view 
       (SELECT id, 
         account_number, 
         market, 
         security_type, 
         market_value, 
         MAX(account_event_date) OVER (PARTITION BY BY account_number, market, security_type, year_month) AS max_event_date, 
         year_month 
       FROM migc_account_statement 
       WHERE year_month = 201507)) a 
GROUP BY account_number, 
     market, 
     security_type, 
     isincount, 
     totalcount, 
     zero_market_value, 
     mon_end_value; 

um es einfacher zu lesen zu machen, würde ich vorschlagen, Unterabfrage Factoring mit (auch bekannt als die Klausel, auch bekannt als Common Table Expressions aka CTE), so dass es so etwas wie aussehen:

WITH results_with_max_dt AS (SELECT id, 
            account_number, 
            market, 
            security_type, 
            market_value, 
            MAX(account_event_date) OVER (PARTITION BY BY account_number, market, security_type, year_month) AS max_event_date, 
            year_month 
          FROM migc_account_statement 
          WHERE year_month = 201507), 
     conditional_values AS (SELECT a.account_number, 
            a.market, 
            a.security_type, 
            a.max_event_date, 
            COUNT(CASE WHEN a.security_type is not NULL 
                AND a.account_event_date = max_event_date THEN ID END) 
             OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS isincount, 
            COUNT(DISTINCT NVL(a.account_event_date, DATE '1800-01-01')) 
             OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS totalcount, 
            COUNT(CASE WHEN a.security_type is not NULL 
                AND a.account_event_date = max_event_date 
                AND a.market_value = 0 THEN ID END) 
             OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS zero_market_value, 
            SUM(CASE WHEN a.security_type is not NULL 
                AND a.account_event_date = max_event_date THEN a.market_value END) 
             OVER (PARTITION BY a.account_number, a.market, a.security_type, a.year_month) AS mon_end_value 
          FROM results_with_max_dt a) 
SELECT account_number, 
     market, 
     security_type, 
     SUM(CASE WHEN a.security_type is not NULL THEN market_value END) AS total_market_value, 
     isincount, 
     totalcount, 
     zero_market_value, 
     mon_end_value 
FROM conditional_values 
GROUP BY account_number, 
     market, 
     security_type, 
     isincount, 
     totalcount, 
     zero_market_value, 
     mon_end_value; 

N.B. Die obigen Abfragen sind nicht getestet. Beachten Sie auch, dass ich die einfachen Anführungszeichen aus der Zeit um 201507 entfernt habe, da die Spalte year_month den Datentyp NUMBER gemäß der von Ihnen bereitgestellten Tabellen-DDL aufweist.

Verwandte Themen