Каковы подводные камни использования sql_variant? - PullRequest
10 голосов
/ 20 октября 2011

Я несколько раз читал и слышал, что sql_variant следует избегать. Я думаю, у меня есть отличный вариант для этого. В прошлом я использовал varchar(max) для хранения разных типов в одном и том же столбце, но кажется разумным избежать издержек де / сериализации, когда есть встроенный тип, который делает именно то, что я хочу.

Итак, что именно является ловушками использования sql_variant? Связаны ли они с производительностью, с ошибками в программировании или с чем-то еще? Кстати, я буду взаимодействовать с этим столбцом из клиентского кода и функций CLR, если это то, что нужно учитывать.

Ответы [ 4 ]

4 голосов
/ 11 августа 2015

Хранение различных типов в одном и том же столбце с помощью SQL_VARIANT - это почти то же самое, что и приведение всего к Object в .NET. И иногда есть веские причины для использования этого типа, поскольку он, безусловно, может предусматривать более общую программную структуру.

Однако, как вы и ожидали, при использовании SQL_VARIANT есть некоторые подводные камни, о которых вам следует знать, тем более что одна из них может нарушить условия сделки:

  1. Точно так же, как приведение всего к Object в .NET (и, возможно, требующий упаковки / распаковки в зависимости от базового типа), при использовании SQL_VARIANT наблюдается определенное снижение производительности. В зависимости от варианта использования может быть приемлемым снижение производительности, если функциональность действительно в этом нуждается и / или использование не очень частое (т.е. много раз в секунду).

  2. В отличие от преобразования данных в Object в .NET, тип данных SQL_VARIANT имеет ограничения относительно того, какие базовые типы данных он может содержать. Следующие типы данных не могут быть сохранены как SQL_VARIANT:

    • VARCHAR(MAX)
    • NVARCHAR(MAX)
    • VARBINARY(MAX)
    • XML
    • TIMESTAMP / ROWVERSION
    • TEXT (вы не должны использовать этот тип в SQL Server 2005)
    • NTEXT (вы не должны использовать этот тип в SQL Server 2005)
    • IMAGE (вы не должны использовать этот тип в SQL Server 2005)

    Это ограничение может легко предотвратить возможность использования SQL_VARIANT, если существует требование для хранения любого из этих типов данных. Обратите внимание, что проблема здесь заключается в базовом типе данных и , а не размере данных, как показывает следующий тест:

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

    Возвращает:

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

Справедливости ради, одно преимущество использования SQL_VARIANT перед приведением всего к NVARCHAR состоит в том, что SQL_VARIANT сохраняет информацию о базовом типе и обеспечивает его использование, так что вы не можете легко использовать значения в совершенно неподходящих контекстах.

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;

Возвращает:

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.

Относительно невозможности использовать SQL_VARIANT в качестве PK: это действительно не проблема, поскольку сама природа универсального типа данных в значительной степени исключает его нежелательность в первую очередь для такого использования.

Относительно невозможности использования SQL_VARIANT с оператором LIKE: это в основном не проблема из-за возможности преобразовать его в соответствующий тип, который работает с LIKE, как в:

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

Вышеуказанное, безусловно, не самое эффективное, но оно функционально, и, как уже упоминалось выше, эффективность уже была исключена, поскольку она была принесена в жертву в обмен на функциональность при решении использовать тип данных SQL_VARIANT.

2 голосов
/ 01 августа 2015

Это также облегчает возникновение ошибок программирования.АБД / Программист смотрит на столбец, и он выглядит как целое число, поэтому он помещает в него целое число, но дальше процесс хочет, чтобы это была строка.Я видел это с плохо написанным импортом в столбцы sql_variant.

1 голос
/ 01 февраля 2015

Я видел как проблемы с производительностью, так и проблемы с качеством кода:

В большинстве случаев, когда вы получаете доступ к этому полю, вам придется проверять тип (используя sql_variant_property).Это делает ваши запросы более сложными, что может вызвать обе проблемы, которые вы перечислите.

Вам также придется приводить это поле каждый раз, когда вы его используете, вызывая дальнейшее снижение производительности.

Далее,Столбцы sql_variant не могут быть частью первичного ключа, они не работают как часть вычисляемого столбца и не работают с LIKE в предложении WHERE.

0 голосов
/ 20 октября 2011

Единственная очевидная ловушка, которая приходит на ум, - это ситуации, когда у вас есть значения, которые вы хотите вставить в поле sql_variant, которое превышает его максимальную длину (8016 байт, для каждой веб-страницы: http://msdn.microsoft.com/en-us/library/ms173829.aspx). Если ваши значения никогда не приближайтесь к этому пределу, тогда sql_variant может быть очень хорошим подходом. Иначе, вы все равно можете использовать sql_variant, но предоставить отдельное битовое поле «isBlob», которое указывает на отдельную таблицу с вашими значениями varbinary (max) (например,).

...