Gestione di dati di tipo ntext, text e image

Nota importanteImportante

Questa caratteristica verrà rimossa a partire da una delle prossime versioni di Microsoft SQL Server. Evitare di utilizzare questa funzionalità in un nuovo progetto di sviluppo e prevedere interventi di modifica nelle applicazioni in cui è attualmente implementata. Utilizzare preferibilmente i tipi di dati varchar(max), nvarchar(max) e varbinary(max). Per ulteriori informazioni, vedere Utilizzo di tipi di dati per valori di grandi dimensioni.

I tipi di dati ntext, text e image di SQL Server consentono di includere in un unico valore quantità di dati estremamente elevate, fino a 2 GB. Un singolo valore è in genere di dimensioni troppo grandi per poter essere recuperato da un'applicazione in una sola operazione; alcuni valori possono avere una dimensione superiore a quella della memoria virtuale disponibile nel client. Il recupero di tali valori pertanto richiede in genere procedure speciali.

Se un valore di tipo ntext, text e image non supera le dimensioni di una stringa Unicode, di caratteri o binaria (rispettivamente 4.000 caratteri, 8.000 caratteri e 8.000 byte), è possibile farvi riferimento in istruzioni SELECT, UPDATE e INSERT in base alle stesse modalità utilizzate per i tipi di minori dimensioni. Nell'elenco di selezione di un'istruzione SELECT, ad esempio, è possibile fare riferimento a una colonna di tipo ntext con un valore di dimensioni ridotte in base alle stesse modalità con cui si fa riferimento a una colonna di tipo nvarchar. È tuttavia necessario rispettare alcune limitazioni. Non è consentito, ad esempio, fare riferimento direttamente a colonne di tipo ntext, text o image in una clausola WHERE. Tali colonne possono essere incluse in una clausola WHERE come parametri di una funzione che restituisce un altro tipo di dati, ad esempio ISNULL, SUBSTRING o PATINDEX, oppure in un'espressione IS NULL, IS NOT NULL o LIKE.

Gestione di valori di dimensioni maggiori

Se i valori di tipo ntext, text e image assumono dimensioni maggiori, è tuttavia necessario gestirli a blocchi. Transact-SQL e le API di database includono funzioni che consentono alle applicazioni di utilizzare i dati di tipo ntext, text e image a blocchi.

Le API di database seguono uno schema comune per la gestione di colonne di tipo ntext, text e image di grandi dimensioni:

  • Per leggere una colonna di tipo ntext, text o image di grandi dimensioni in un'applicazione, la colonna viene inclusa in un elenco di selezione e associata a una variabile di programma di dimensioni sufficienti per contenere un blocco di dati di dimensioni elevate. L'applicazione esegue quindi l'istruzione e utilizza una funzione o un metodo API per recuperare i dati, un blocco alla volta, nella variabile associata.

  • Per scrivere in una colonna di grandi dimensioni, l'applicazione esegue un'istruzione INSERT o UPDATE con un indicatore di parametro (?) al posto del valore da inserire nella colonna di tipo ntext, text o image. L'indicatore di parametro (oppure, nel caso di ADO, il parametro) viene associato a una variabile di programma di dimensioni sufficienti per contenere i blocchi di dati. L'applicazione esegue un ciclo nell'ambito del quale trasferisce innanzitutto il blocco di dati successivo nella variabile associata, e quindi chiama una funzione o un metodo API per scrivere tale blocco di dati. Il ciclo viene ripetuto fino a quando non è stato inviato l'intero valore.

Utilizzo dell'opzione text in row

In SQL Server è possibile attivare l'opzione text in row in una tabella per consentire l'archiviazione di dati di tipo text, ntext o image nella riga di dati di tale tabella.

Per attivare l'opzione, eseguire la stored procedure sp_tableoption specificando text in row come nome dell'opzione e on come valore corrispondente. Le dimensioni massime predefinite per una riga di dati BLOB (Binary Large Object), ad esempio dati di tipo text, ntext o image, sono pari a 256 byte, con valori possibili compresi tra 24 e 7000 byte. Per impostare dimensioni massime diverse da quelle predefinite, specificare come valore dell'opzione un numero intero compreso nell'intervallo indicato.

Le stringhe di tipo text, ntext o image vengono archiviate nella riga di dati solo se si verificano le condizioni seguenti:

  • L'opzione text in row è attivata.

  • La lunghezza della stringa è inferiore al valore limite specificato in @OptionValue.

  • Nella riga di dati lo spazio disponibile è sufficiente.

Quando vengono memorizzate stringhe BLOB nella riga di dati, le operazioni di lettura e scrittura delle stringhe di tipo text, ntext o image vengono eseguite tanto rapidamente quanto le operazioni di lettura e scrittura di stringhe di caratteri e binarie. Per la lettura o la scrittura di stringhe BLOB, infatti, SQL Server non deve accedere a pagine distinte.

Se le dimensioni di una stringa di tipo text, ntext o image sono maggiori del limite specificato o dello spazio disponibile nella riga, vengono memorizzati solo i puntatori. Le condizioni per l'archiviazione delle stringhe BLOB nella riga devono comunque essere soddisfatte, ovvero lo spazio disponibile nella riga di dati deve essere sufficiente per includervi i puntatori.

Per ulteriori informazioni, vedere sp_tableoption (Transact-SQL).

Utilizzo dei puntatori di testo

Se non viene specificata l'opzione text in row, le stringhe di tipo text, ntext o image vengono archiviate all'esterno della riga di dati, nella quale vengono invece inclusi solo i puntatori a tali stringhe. I puntatori di testo fanno riferimento al nodo radice di un albero costituita da puntatori interni mappati alle pagine in cui sono effettivamente archiviati frammenti di stringhe di dati di tipo text, ntext e image.

I puntatori di testo all'interno di righe di SQL Server 2000 sono diversi dai puntatori di testo delle versioni precedenti di SQL Server. I puntatori di testo all'interno di righe funzionano in modo analogo agli handle di file per dati BLOB, mentre i puntatori di testo delle versioni precedenti funzionano come indirizzi dei dati BLOB. Quando si utilizzano i puntatori di testo all'interno di righe, è pertanto necessario tenere conto dei fattori seguenti:

Nota importanteImportante

Sebbene il testo all'interno di righe sia consentito in un cursore, un puntatore di testo all'interno di righe non lo è. SQL Server restituisce l'errore 328 se si tenta di dichiarare un cursore che include un puntatore di testo all'interno di righe.

  1. Numero

    Per ogni transazione di un database sono consentiti al massimo 1024 puntatori di testo all'interno di righe attivi.

  2. Utilizzo di blocchi

    Se un utente ottiene un puntatore di testo attivo, in SQL Server 2000 la riga di dati viene bloccata per evitare che altri utenti possano modificarla o eliminarla mentre il puntatore è utilizzato dal primo utente. Il blocco viene rilasciato quando il puntatore di testo non è più valido. Per invalidare un puntatore di testo, utilizzare sp_invalidate_textptr (Transact-SQL).

    Non è possibile utilizzare un puntatore di testo per aggiornare valori BLOB se il livello di isolamento della transazione è Read uncommitted oppure il database è in modalità sola lettura.

    In SQL Server 2000 la riga di dati non viene bloccata se il database è in modalità utente singolo.

    Si consideri ad esempio la tabella seguente:

    CREATE TABLE t1 (c1 int, c2 text)
    EXEC sp_tableoption 't1', 'text in row', 'on'
    INSERT t1 VALUES ('1', 'a')
    

    La transazione seguente viene eseguita correttamente:

    INSERT t1 VALUES ('1','This is text.')
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    GO
    BEGIN TRAN
    DECLARE @ptr varbinary(16)
    SELECT @ptr = textptr(c2)
    FROM t1
    WHERE c1 = 1;
    READTEXT t1.c2 @ptr 0 5
    COMMIT TRAN
    GO
    

    La transazione seguente ha invece esito negativo:

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    GO
    BEGIN TRAN
    DECLARE @ptr varbinary(16)
    SELECT @ptr = textptr(c2)
    FROM t1
    WHERE c1 = 1
    WRITETEXT t1.c2 @ptr 'xx'
    COMMIT TRAN
    GO
    
  3. Durata

    I puntatori di testo all'interno di righe sono validi solo all'interno di una transazione. Quando viene eseguito il commit della transazione, il puntatore di testo viene invalidato.

    Durante una transazione i puntatori di testo all'interno di righe possono essere invalidati in corrispondenza di una delle azioni seguenti:

    • La sessione viene interrotta.

    • La riga di dati viene eliminata durante la stessa transazione (nelle altre transazioni la riga di dati non può essere eliminata a causa del blocco ottenutovi).

    • Lo schema di una tabella in cui risiede il puntatore di testo viene modificato. Le azioni di modifica dello schema che invalidano i puntatori di testo sono la creazione o l'eliminazione di un indice cluster, la modifica o l'eliminazione della tabella, il troncamento della tabella, la modifica dell'opzione text in row tramite sp_tableoption e l'esecuzione di sp_indexoption.

    Riprendendo l'esempio precedente, lo script seguente genera un errore in SQL Server 2000, mentre funziona correttamente nelle versioni precedenti di SQL Server.

    DECLARE @ptrval varbinary(16)
    PRINT 'get error here'
    SELECT @ptrval = TEXTPTR(c2)
    FROM t1
    WHERE c1 = 1
    READTEXT t1.c2 @ptrval 0 1
    

    In SQL Server 2000 il puntatore di testo all'interno di righe deve essere utilizzato all'interno di una transazione:

    BEGIN TRAN
    DECLARE @ptrval varbinary(16)
    SELECT @ptrval = TEXTPTR(c2)
    FROM t1
    WHERE c1 = 1
    READTEXT t1.c2 @ptrval 0 1
    COMMIT
    
  4. Testo NULL

    È possibile ottenere un puntatore di testo all'interno di righe per il testo NULL generato da INSERT. In precedenza era possibile ottenere puntatori di testo solo dopo avere aggiornato un valore BLOB in modo da renderlo NULL.

    Il codice seguente non viene ad esempio eseguito in SQL Server 7.0, mentre funziona correttamente in SQL Server 2000.

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    GO
    INSERT INTO t1 VALUES (4, NULL)
    BEGIN TRAN
    DECLARE @ptrval VARBINARY(16)
    SELECT @ptrval = TEXTPTR(c2)
    FROM t1
    WHERE c1 = 4
    WRITETEXT t1.c2 @ptrval 'x4'
    COMMIT
    

    In SQL Server 7.0 è necessario procedere nel modo seguente:

    INSERT INTO t1 VALUES (4, NULL)
    UPDATE t1 
       SET c2 = NULL 
       WHERE c1 = 4
    DECLARE @ptrval VARBINARY(16)
    SELECT @ptrval = TEXTPTR(c2)
    FROM t1
    WHERE c1 = 4
    WRITETEXT t1.c2 @ptrval 'x4'
    

Nella tabella seguente vengono descritte le differenze tra un puntatore all'interno di righe e un puntatore esterno.

Differenza

Puntatore di testo all'interno di righe

Puntatore di testo non all'interno di righe

Numero

Massimo 1024 puntatori attivi per transazione e per database.

Numero illimitato di puntatori attivi.

Utilizzo di blocchi

La riga di dati viene bloccata (con blocco S) finché il puntatore non viene invalidato.

I blocchi non vengono ottenuti se la transazione è Read uncommitted oppure il database è in modalità utente singolo o sola lettura.

La riga di dati non viene bloccata.

Durata

Viene invalidato al termine della transazione o della sessione, in corrispondenza dell'eliminazione di una riga o quando lo schema della tabella viene modificato.

Viene invalidato in corrispondenza dell'eliminazione della riga.

Testo NULL

Ottenibile subito dopo l'inserimento di testo NULL.

Ottenibile solo in seguito all'aggiornamento.

Utilizzo di dati di tipo ntext, text e image con API di database

Di seguito viene fornito un riepilogo delle modalità di gestione dei dati di tipo ntext, text e image utilizzate dalle API di database:

  • ADO

    ADO può eseguire il mapping dei parametri o delle colonne di tipo ntext, text o image a un oggetto Field o Parameter. Utilizzare il metodo GetChunk per recuperare i dati un blocco alla volta e il metodo AppendChunk per scrivere i dati un blocco alla volta.

  • OLE DB

    OLE DB utilizza l'interfaccia ISequentialStream per supportare i tipi di dati ntext, text e image. Il metodo ISequentialStream::Read legge i dati di tipo long un blocco alla volta, mentre ISequentialStream::Write li scrive nel database un blocco alla volta. Per ulteriori informazioni, vedere Oggetti BLOB e OLE

  • ODBC

    ODBC include la funzionalità "data-at-execution" che consente di gestire i tipi di dati ODBC per dati di tipo long: SQL_WLONGVARCHAR (ntext), SQL_LONGVARCHAR (text) e SQL_LONGVARBINARY (image). Questi tipi di dati vengono associati a una variabile di programma. Vengono quindi chiamate le procedure SQLGetData e SQLPutData che consentono rispettivamente di recuperare e inviare i dati di tipo long un blocco alla volta. Per ulteriori informazioni, vedere Gestione di colonne di tipo text e image.

  • DB-Library

    L'associazione delle colonne di tipo ntext, text e image a variabili di programma viene eseguita anche nelle applicazioni DB-Library. La funzione dbtxtptr di DB-Library consente di ottenere un puntatore alla posizione dell'occorrenza della colonna di tipo long nel database, mentre la funzione dbreadtext consente di leggere i dati di tipo long un blocco alla volta. Altre funzioni, ad esempio dbwritetext, dbupdatetext e dbmoretext, consentono di scrivere i dati di tipo long un blocco alla volta.

    [!NOTA]

    L'accesso al testo all'interno di righe con DB-Library non è supportato.

Per ulteriori informazioni, vedere Funzioni per i valori text e image (Transact-SQL).