2011-10-20 3 views
8

Ho letto e sentito più volte che è necessario evitare sql_variant. Penso di avere un ottimo uso per questo. In passato ho utilizzato varchar(max) per memorizzare diversi tipi nella stessa colonna, ma sembra ragionevole evitare l'overhead di de/serializzazione quando c'è un tipo incorporato che fa esattamente ciò che voglio.Quali sono le insidie ​​nell'usare sql_variant?

Quindi, che cosa esattamente sono le insidie ​​dell'utilizzo di sql_variant? Sono prestazioni correlate, errori di programmazione facili da fare o qualcos'altro? Per inciso, interagirò con questa colonna dal codice client e dalle funzioni CLR, se questo è qualcosa da considerare.

+0

Perché stai memorizzando tipi diversi nella stessa colonna? Si tratta di una struttura 'EAV'? –

+0

No. Non voglio davvero sviarmi con la validità del mio caso d'uso, ma ho una tabella di filtri che può essere applicata a varie colonne. Quindi i valori comparabili sono di diversi tipi. – Daniel

risposta

0

L'unica trappola evidente che viene in mente è nelle situazioni in cui si hanno valori che si desidera inserire nel campo sql_variant che superano la lunghezza massima (8016 byte, per questa pagina Web: http://msdn.microsoft.com/en-us/library/ms173829.aspx). Se i tuoi valori non si avvicinano mai a quel limite, sql_variant può essere un ottimo approccio. Altrimenti, potresti comunque utilizzare sql_variant, ma fornire un campo di bit "isBlob" separato che punta a una tabella separata con i valori varbinary (max) (ad esempio).

1

ho visto entrambi i problemi di prestazioni e di codici di qualità relativi problemi:

maggior parte delle volte si accede a questo campo, si sta andando ad avere per controllare il tipo (utilizzando sql_variant_property). Questo rende le tue domande più complesse, il che può causare entrambi i problemi elencati.

Avrete anche per lanciare questo campo ogni volta che lo si utilizza, provocando un ulteriore penalizzazione delle prestazioni.

Inoltre, le colonne sql_variant non possono far parte di una chiave primaria, non funzionano come parte di una colonna calcolata e non funzionano con LIKE in una clausola WHERE.

1

E rende anche più facile per gli errori di programmazione che si verifichi. Un DBA/programmatore guarda una colonna e sembra un numero intero, quindi inserisce un numero intero, ma più in basso nella riga un processo vuole che sia una stringa. Ho visto questo con importazioni scritte male in colonne sql_variant.

1

Memorizzare diversi tipi nella stessa colonna tramite SQL_VARIANT è quasi la stessa cosa di trasmettere tutto a Object in .NET. E a volte ci sono validi motivi per utilizzare questo tipo in quanto può certamente consentire una struttura programmatica più generica.

Tuttavia, come si stava anticipando, ci sono alcune insidie ​​di utilizzare SQL_VARIANT che si dovrebbe essere a conoscenza, tanto più che uno di loro potrebbe essere un affare-breaker:

  1. Proprio come la fusione di tutto per Object in .NET (e possibilmente richiedendo boxing/unboxing a seconda del tipo di base), si verifica un netto calo di prestazioni quando si utilizza SQL_VARIANT. A seconda del caso d'uso, potrebbe essere accettabile avere prestazioni ridotte se la funzionalità ne ha davvero bisogno e/o l'uso non è molto frequente (cioè molte volte al secondo).

  2. differenza colata tutto Object NET, il tipo di dati SQL_VARIANT ha limitazioni su ciò tipi di dati di base può contenere.I seguenti tipi di dati non possono essere memorizzati come SQL_VARIANT:

    • VARCHAR(MAX)
    • NVARCHAR(MAX)
    • VARBINARY(MAX)
    • XML
    • TIMESTAMP/ROWVERSION
    • TEXT (Si consiglia di non fare uso di questo tipo in ogni caso come di SQL Server 2005)
    • NTEXT (non si dovrebbe usare questo tipo comunque come di SQL Server 2005)
    • IMAGE (non si dovrebbe usare questo tipo comunque come di SQL Server 2005)

    Questa limitazione può facilmente prevenire la possibilità di utilizzare SQL_VARIANT se è necessario memorizzare uno qualsiasi di questi tipi di dati. Si prega di notare che il problema qui è il tipo di dati di base e non la dimensione dei dati, come il seguente test mostra:

    DECLARE @tmp1 TABLE (col1 SQL_VARIANT NOT NULL); 
    INSERT INTO @tmp1 (col1) VALUES (CONVERT(VARCHAR(MAX), 'g')); 
    

    Returns:

    Msg 206, Level 16, State 2, Line 2 
    Operand type clash: varchar(max) is incompatible with sql_variant 
    

Per essere onesti, una Il vantaggio dell'utilizzo di SQL_VARIANT durante la trasmissione di tutto su NVARCHAR è che SQL_VARIANT conserva le informazioni sul tipo sottostante e ne impone l'utilizzo in modo da non poter facilmente utilizzare i valori in contesti completamente inappropriati.

DECLARE @tmp2 TABLE (col1 SQL_VARIANT NOT NULL); 
INSERT INTO @tmp2 (col1) VALUES (1); 

SELECT CONVERT(DATETIME, col1) FROM @tmp2; 

SELECT CONVERT(TIME, col1) FROM @tmp2; 

Returns:

1900-01-02 00:00:00.000 

Msg 529, Level 16, State 3, Line 6 
Explicit conversion from data type int to time is not allowed. 

quanto riguarda non essere in grado di utilizzare SQL_VARIANT come PK: questo è davvero un non-problema in quanto la natura stessa di un tipo di dati generici esclude praticamente che venga auspicabile in il primo posto per un tale uso.

Riguardo non poter utilizzare SQL_VARIANT con un operatore LIKE: questo è principalmente un non-problema a causa di essere in grado di convertirlo in un tipo appropriato che non funziona con LIKE, come in:

WHERE CONVERT(NVARCHAR(50), [sql_variant_field]) LIKE '%something%' 

Quanto sopra non è certamente il più efficiente, ma è funzionale, e come detto sopra, l'efficienza era già stata esclusa poiché veniva sacrificata in cambio di funzionalità al momento di decidere di utilizzare il tipo di dati SQL_VARIANT.