Sto utilizzando Oracle 11g, la tabella principale ha circa 10 milioni di record. Qui è la mia domanda:Un problema di prestazioni oracle su COUNT()
SELECT COUNT (*)
FROM CONTACT c INNER JOIN STATUS S ON C.STATUS = S.STATUS
WHERE C.USER = 1 AND S.REQUIRE = 1 AND ROWNUM = 1;
Il costo è di 3736, ma quando l'ho cambiato in questa forma:
SELECT COUNT (*) FROM
(SELECT 1 FROM CONTACT c INNER JOIN STATUS S ON C.STATUS = S.STATUS
WHERE C.USER = 1 AND S.REQUIRE = 1 AND ROWNUM = 1);
Il costo è diventato 5! Qual è la differenza tra queste 2 domande?
Ecco il piano di spiegare sia per query:
La prima query:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 3736 (1)| 00:00:45 |
| 1 | SORT AGGREGATE | | 1 | 10 | | |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | NESTED LOOPS | | 4627 | 46270 | 3736 (1)| 00:00:45 |
| 4 | TABLE ACCESS BY INDEX ROWID| CONTACT | 6610 | 33050 | 3736 (1)| 00:00:45 |
|* 5 | INDEX RANGE SCAN | IX_CONTACT_USR | 6610 | | 20 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX_CONTACT_STATUS | 1 | 5 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM=1)
5 - access("C"."USER"=1)
6 - access("C"."STATUS"="S"."STATUS" AND "S"."REQUIRE"=1)
La seconda query:
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 5 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | | |
| 2 | VIEW | | 1 | | 5 (0)| 00:00:01 |
|* 3 | COUNT STOPKEY | | | | | |
| 4 | NESTED LOOPS | | 2 | 20 | 5 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| CONTACT | 3 | 15 | 5 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX_CONTACT_USR | 6610 | | 3 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IX_CONTACT_STATUS | 1 | 5 | 0 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(ROWNUM=1)
6 - access("C"."USER"=1)
7 - access("C"."STATUS"="S"."STATUS" AND "S"."REQUIRE"=1)
ho eseguito 2 domande, la prima a volte 45s costo + (ad esempio, prima eseguire o modificare l'id utente), altrimenti costerà < 1s. Non so perché è così diverso, forse la cache di db?
Quando ho eseguito la seconda query, posso sempre ottenere risultato in 1 s. Quindi penso che il secondo sia migliore, ma non è il motivo per cui migliora di molto.
Commento sul piano di spiegazioni fornite: Come supponevo, i tuoi due querries non saranno diversi. L'unica differenza è la linea 2 - e ciò non influirà sulle prestazioni ... (notare anche che spiegare piano non è sempre quello che si otterrà in runtime - ecco perché ho proposto di rintracciarlo. – igr
Bella domanda e sicuramente otterrà risposte diverse !Sono contento che tu abbia inserito i piani non molti fanno ed è frustrante, più 1 solo per quello! – glh
puoi pubblicare il piano di spiegazioni per entrambe le query che ci aiuterà a comprendere meglio le statistiche della tabella e confrontare le due query. Per ottenere spieghi il piano di query, segui questo link: http://www.oraclebin.com/2012/12/explain-plan-how-to-get-execution-plan.html –