Oracle
 sql >> Database >  >> RDS >> Oracle

Procedura memorizzata Oracle, che restituisce il cursore di riferimento rispetto agli array associativi

La richiesta del DBA non ha senso.

Quello che il DBA sta quasi sicuramente pensando è che vuole ridurre al minimo il numero di spostamenti di contesto del motore da SQL a PL/SQL che si verificano quando si recuperano i dati da un cursore. Ma la soluzione suggerita è scarsamente mirata a questo particolare problema e introduce altri problemi di prestazioni molto più seri nella maggior parte dei sistemi.

In Oracle, si verifica un cambio di contesto da SQL a PL/SQL quando la VM PL/SQL richiede più dati alla VM SQL, la VM SQL risponde eseguendo ulteriormente l'istruzione per ottenere i dati che quindi impacchetta e restituisce al PL /VM SQL. Se il motore PL/SQL richiede le righe una alla volta e stai recuperando molte righe, è possibile che questi cambiamenti di contesto possano rappresentare una frazione significativa del tuo runtime complessivo. Per combattere questo problema, Oracle ha introdotto il concetto di operazioni in blocco almeno nei giorni 8i. Ciò ha consentito alla VM PL/SQL di richiedere più righe alla volta dalla VM SQL. Se la VM PL/SQL richiede 100 righe alla volta, hai eliminato il 99% dei cambiamenti di contesto e il tuo codice potrebbe essere eseguito molto più velocemente.

Una volta introdotte le operazioni in blocco, c'era molto codice che poteva essere rifattorizzato per essere più efficiente utilizzando esplicitamente BULK COLLECT operazioni anziché recuperare riga per riga e quindi utilizzare FORALL loop per elaborare i dati in quelle raccolte. Entro 10,2 giorni, tuttavia, Oracle aveva integrato le operazioni in blocco in FOR implicito esegue il loop in modo da un implicito FOR loop ora raccoglie automaticamente in blocco in batch di 100 anziché recuperare riga per riga.

Nel tuo caso, tuttavia, poiché stai restituendo i dati a un'applicazione client, l'uso di operazioni in blocco è molto meno significativo. Qualsiasi API lato client decente avrà funzionalità che consentono al client di specificare quante righe devono essere recuperate dal cursore in ogni round trip di rete e quelle richieste di recupero andranno direttamente alla VM SQL, non tramite il PL /SQL VM, quindi non ci sono spostamenti di contesto da SQL a PL/SQL di cui preoccuparsi. La tua applicazione deve preoccuparsi di recuperare un numero appropriato di righe in ogni viaggio di andata e ritorno, abbastanza che l'applicazione non diventi troppo loquace e collo di bottiglia sulla rete, ma non così tante da dover aspettare troppo a lungo prima che i risultati siano restituito o per memorizzare troppi dati in memoria.

Restituire raccolte PL/SQL anziché un REF CURSOR a un'applicazione client non ridurrà il numero di cambiamenti di contesto che si verificano. Ma avrà un sacco di altri aspetti negativi, non ultimo l'utilizzo della memoria. Una raccolta PL/SQL deve essere archiviata interamente nell'area globale del processo (PGA) (assumendo connessioni server dedicate) sul server di database. Questo è un pezzo di memoria che deve essere allocato dalla RAM del server. Ciò significa che il server dovrà allocare memoria in cui recuperare fino all'ultima riga richiesta da ogni client. Ciò, a sua volta, limiterà drasticamente la scalabilità dell'applicazione e, a seconda della configurazione del database, potrebbe sottrarre RAM ad altre parti del database Oracle, cosa che sarebbe molto utile per migliorare le prestazioni dell'applicazione. E se esaurisci lo spazio PGA, le tue sessioni inizieranno a ricevere errori relativi alla memoria. Anche in applicazioni basate esclusivamente su PL/SQL, non vorresti mai recuperare tutti i dati nelle raccolte, ma vorresti sempre recuperarli in batch più piccoli, al fine di ridurre al minimo la quantità di PGA che stai utilizzando.

Inoltre, il recupero di tutti i dati in memoria renderà l'applicazione molto più lenta. Quasi tutti i framework ti permetteranno di recuperare i dati quando ne hai bisogno, quindi, ad esempio, se hai un report che stai visualizzando in pagine di 25 righe ciascuna, la tua applicazione dovrebbe solo recuperare le prime 25 righe prima di dipingere il prima schermata. E non dovrebbe mai recuperare le 25 righe successive a meno che l'utente non richieda la pagina successiva dei risultati. Se stai recuperando i dati in array come proposto dal tuo DBA, tuttavia, dovrai recuperare tutte le righe prima che l'applicazione possa iniziare a visualizzare la prima riga anche se l'utente non vuole mai vedere più della prima manciata di righe. Ciò significherà molto più I/O sul server del database per recuperare tutte le righe, più PGA sul server, più RAM sul server delle applicazioni per bufferizzare il risultato e attese più lunghe per la rete.