2011-10-20 28 views
8

He leído y oído varias veces que se debe evitar sql_variant. Creo que tengo un buen caso de uso para eso. He usado varchar(max) en el pasado para almacenar diferentes tipos en la misma columna, pero parece sensato evitar la sobrecarga de de/serialización cuando hay un tipo incorporado que hace exactamente lo que quiero.¿Cuáles son los peligros de usar sql_variant?

Entonces, ¿qué exactamente son las trampas de usar sql_variant? ¿Están relacionados con el rendimiento, o errores de programación fáciles de hacer, u otra cosa? A propósito, interactuaré con esta columna desde el código del cliente y las funciones de CLR, si eso es algo a tener en cuenta.

+0

¿Por qué almacena diferentes tipos en la misma columna? ¿Es esto una estructura 'EAV'? –

+0

No. Realmente no me quiero desviar de la validez de mi caso de uso, pero tengo una tabla de filtros que se puede aplicar a varias columnas. Por lo tanto, los valores comparables son de diferentes tipos. – Daniel

Respuesta

0

El único inconveniente obvio que se le ocurre es en situaciones en las que tiene valores que desea insertar en su campo sql_variant que exceden su longitud máxima (8016 bytes, por esta página web: http://msdn.microsoft.com/en-us/library/ms173829.aspx). Si sus valores nunca se acercan a ese límite, entonces sql_variant puede ser un muy buen enfoque. De lo contrario, aún podría usar sql_variant, pero proporcionar un campo de bit "isBlob" separado que apunte a una tabla separada con sus valores varbinary (max) (por ejemplo).

1

que he visto ambos problemas de rendimiento y de códigos relacionados con la calidad problemas:

mayoría de las veces se accede a este campo, se le va a tener que comprobar el tipo (usando sql_variant_property). Esto hace que sus consultas sean más complejas, lo que puede causar los dos problemas que enumera.

También deberá realizar este campo cada vez que lo use, lo que ocasionará una mayor penalización del rendimiento.

Además, las columnas sql_variant no pueden formar parte de una clave principal, no funcionan como parte de una columna calculada y no funcionan con LIKE en una cláusula WHERE.

1

También facilita la programación de errores. Un DBA/Programador mira una columna y se ve como un entero, por lo que pone un número entero en ella, pero más abajo en la línea un proceso quiere que sea una cadena. Lo he visto con importaciones mal escritas en columnas sql_variant.

1

Almacenar diferentes tipos en la misma columna a través de SQL_VARIANT es casi lo mismo que enviar todo a Object en .NET. Y a veces hay razones válidas para usar este tipo, ya que ciertamente puede permitir una estructura programática más genérica.

Sin embargo, a medida que estaban esperando, hay algunas trampas en el uso de SQL_VARIANT que usted debe tener en cuenta, especialmente en lo que uno de ellos podría ser un acuerdo para romper:

  1. Al igual que la fundición todo para Object en .NET (y posiblemente requiera boxeo/unboxing dependiendo del tipo de base), hay un rendimiento definido al usar SQL_VARIANT. Dependiendo del caso de uso, podría ser aceptable tener un rendimiento reducido si la funcionalidad realmente lo necesita y/o el uso no es muy frecuente (es decir, muchas veces por segundo).

  2. A diferencia de la conversión de todo a Object en .NET, el tipo de datos SQL_VARIANT tiene limitaciones con respecto a los tipos de datos base que puede contener.Los siguientes tipos de datos no se pueden almacenar como SQL_VARIANT:

    • VARCHAR(MAX)
    • NVARCHAR(MAX)
    • VARBINARY(MAX)
    • XML
    • TIMESTAMP/ROWVERSION
    • TEXT (que no deberían usar este tipo de todos modos como de SQL Server 2005)
    • NTEXT (que no debe utilizar este tipo de todos modos como de SQL Server 2005)
    • IMAGE (que no debe utilizar este tipo de todos modos como de SQL Server 2005)

    Esta limitación se puede evitar fácilmente la posibilidad de usar SQL_VARIANT si existe la necesidad de almacenar cualquiera de estos tipos de datos. Tenga en cuenta que la cuestión aquí es el tipo de datos base y no el tamaño de los datos, como la prueba siguiente muestra:

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

    Devuelve:

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

Para ser justos, una beneficio de usar SQL_VARIANT sobre la fundición de todo a NVARCHAR es que SQL_VARIANT conserva la información de tipo subyacente e impone su uso para que no pueda utilizar fácilmente los valores en contextos completamente inapropiados.

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; 

Devuelve:

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. 

En cuanto a no poder utilizar SQL_VARIANT como PK: esto es realmente un no-problema ya que la naturaleza misma de un tipo de datos genérico más o menos lo excluye de ser deseable en el primer lugar para tal uso.

En cuanto a no poder utilizar SQL_VARIANT con un operador LIKE: esto es sobre todo un problema no debe de ser capaz de convertirlo a un tipo adecuado que funciona con LIKE, como en:

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

Lo anterior ciertamente no es el más eficiente, pero es funcional, y como se mencionó anteriormente, la eficiencia ya se descartó ya que se sacrificó a cambio de la funcionalidad cuando se decidió utilizar el tipo de datos SQL_VARIANT.

Cuestiones relacionadas