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:
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).
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
.
fonte
2015-08-11 20:07:42
Perché stai memorizzando tipi diversi nella stessa colonna? Si tratta di una struttura 'EAV'? –
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