Ho una tabella con 250.000 righe nel mio database di test. (Ci sono alcune centinaia di milioni in produzione, possiamo osservare lo stesso problema lì.) La tabella ha un identificatore di stringa nvarchar2 (50), non nullo, con un indice univoco su di esso (non è il PK).
Gli identificatori sono costituiti da una prima parte che ha 8 valori diversi nel mio database di test (e circa un migliaio in produzione), quindi un segno @ e infine un numero, compreso tra 1 e 6 cifre. Ad esempio, potrebbero esserci 50 mila righe che iniziano con 'ABCD_BGX1741F_2006_13_20110808.xml @', seguite da 50 mila numeri diversi.
Quando eseguo una query per una singola riga in base al suo identificatore, la cardinalità è stimata come 1, il costo è molto basso, funziona benissimo. Quando eseguo una query per più di una riga con più identificatori in un'espressione IN o un'espressione OR, le stime per l'indice sono completamente errate, quindi viene utilizzata una scansione completa della tabella. Se forzo l'indice con un suggerimento, è molto veloce, la scansione della tabella completa viene effettivamente eseguita con un ordine di grandezza più lento (e molto più lento in produzione). Quindi è un problema di ottimizzazione.
Come test, ho duplicato la tabella (nello stesso schema + tablespace) con lo stesso DDL esatto e lo stesso contenuto esatto. Ho ricreato l'indice univoco sulla prima tabella per buona misura e ho creato lo stesso indice esatto sulla tabella dei cloni. Ho fatto un DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);
. Puoi persino vedere che i nomi degli indici sono consecutivi. Quindi ora l'unica differenza tra le due tabelle è che la prima è stata caricata in ordine casuale per un lungo periodo di tempo, con blocchi sparsi sul disco (in un tablespace insieme a molte altre tabelle di grandi dimensioni), la seconda è stata caricata come una in batch INSERT-SELECT. A parte questo, non riesco a immaginare alcuna differenza. (La tabella originale è stata ridotta dall'ultima grande eliminazione e dopo non è stata eseguita una sola eliminazione.)
Ecco i piani di query per il malato e la tabella dei cloni (le stringhe sotto il pennello nero sono le stesse in tutta l'immagine e anche sotto il pennello grigio.):
(In questo esempio, ci sono 1867 righe che iniziano con l'identificatore con pennello nero. Una query a 2 righe produce una cardinalità di 1867 * 2, una query a 3 righe produce una cardinalità di 1867 * 3, ecc. Impossibile essere una coincidenza, Oracle sembra non curarsi della fine degli identificatori.)
Cosa potrebbe causare questo comportamento? Ovviamente sarebbe piuttosto costoso ricreare la tabella in produzione.
USER_TABLES: http://i.stack.imgur.com/nDWze.jpg USER_INDEXES: http://i.stack.imgur.com/DG9um.jpg Ho modificato solo lo schema e il nome del tablespace. Puoi vedere che i nomi di tabella e indice sono gli stessi dello screenshot del piano di query.