最近、Microsoftが使用しないようにアドバイスしているいくつかの機能について説明しましたが、存在することも忘れておく必要があると思います。同僚が非推奨の下位互換性ビューsys.sysprocesses
を絶えず宣伝している場合がありました 新しい動的管理ビュー(DMV)の代わりに、別の同僚がSQLServerProfilerを使用して運用サーバーを停止した別のケース。
忘れてしまった最新の慣らしは、ntext
を使用した新しいストアドプロシージャです。 パラメータ。チェックしたところ、確かに、データ型は基になるテーブルのスキーマと一致しています。私の心は、これらの古いデータ型について競争を始め、なぜそれらをもう使用すべきではないのかを説明しました:
- 画像
- ntext
- テキスト
これらのタイプは、多くの理由で非推奨リストに含まれており、置き換えられて以来、そのリストに恒久的な位置を占めています。 max
による タイプはSQLServer2005にさかのぼります。これらの問題点のいくつかは次のとおりです。
-
LEFT()
のような多くの文字列関数を使用することはできません 、RTRIM()
、UPPER()
、およびほとんどの比較演算子。 -
TEXTPTR
などの関数を使用する必要があります 、WRITETEXT
、およびUPDATETEXT
変更用。 - 型をローカル変数として使用することはできません。
-
DISTINCT
の列を参照することはできません 、GROUP BY
、ORDER BY
、または含まれている列として(これらのいずれかを実行する必要があるわけではありません)。 - 行に収まる小さな値は、
text in row
でのみ可能です。 オプション。
これは完全なリストではありません。あなたが多かれ少なかれ重要であると考えるかもしれない他の違いがあります。私にとって最も差し迫った理由は、テーブルにこれらのデータ型のいずれかが含まれている場合、クラスター化されたインデックスをオンラインで再構築できないことです。
いくつかのテーブルを使用して単純なデータベースを作成しましょう:
CREATE DATABASE BadIdeas; GO USE BadIdeas; GO CREATE TABLE dbo.t1(id bigint IDENTITY PRIMARY KEY, msg nvarchar(max)); CREATE TABLE dbo.t2(id bigint IDENTITY PRIMARY KEY, msg ntext);>
それでは、テーブルに対してオンライン操作を実行してみましょう。
ALTER TABLE dbo.t1 REBUILD WITH (ONLINE = ON); GO ALTER TABLE dbo.t2 REBUILD WITH (ONLINE = ON);
最初のステートメントは成功しますが、2番目のステートメントは次のようなエラーメッセージを生成します:
メッセージ2725、レベル16、状態2インデックスにデータ型text、ntext、image、またはFILESTREAMの列「msg」が含まれているため、インデックス「PK__t2__3213E83FEEA1E0AD」に対してオンライン操作を実行できません。非クラスター化インデックスの場合、列はインデックスのインクルード列である可能性があります。クラスタ化インデックスの場合、列はテーブルの任意の列にすることができます。 DROP_EXISTINGが使用されている場合、列は新しいインデックスまたは古いインデックスの一部である可能性があります。操作はオフラインで実行する必要があります。
1回限りのシナリオでは、エラーメッセージは簡単に処理できます。テーブルをスキップするか、テーブルを完全に再構築する必要がある場合は、チームと協力して停止をスケジュールします。インデックスメンテナンスソリューションを自動化したり、環境全体に新しい圧縮設定を展開したりする場合、ソリューションに現在または将来の状態を処理させるのは、少し面倒です。
どうすればよいですか?
これらの列をより新しい対応する列に置き換え始めることができます。 sys.columns
を使用してそれらを追跡するのに役立つクエリを次に示します。 カタログビューですが、アプリケーションコードに存在する可能性のある明示的な参照については自分で判断してください:
SELECT [Schema] = s.name, [Object] = o.name, [Column] = c.name, [Data Type] = TYPE_NAME(c.user_type_id) + CASE WHEN c.system_type_id <> c.user_type_id THEN N' (' + TYPE_NAME(c.system_type_id) + N')' ELSE N'' END FROM sys.columns AS c INNER JOIN sys.objects AS o ON c.[object_id] = o.[object_id] INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] WHERE c.system_type_id IN (34, 35, 99) ORDER BY [Schema], [Object], [Column];
出力:
SSMSにアクセスして、これらの列のデータ型を手動で変更したくなるかもしれませんが、他の影響もある可能性があります。たとえば、列にデフォルトの制約が関連付けられている場合があります。また、タンデムで更新する必要のあるパラメーターを持つストアドプロシージャがある場合があります:
CREATE PROCEDURE dbo.sp1 @p1 ntext AS PRINT 1; GO
これらすべてのケースを見つけるには、上記のクエリを適用してsys.parameters
を検索します。 代わりにカタログビュー:
SELECT [Schema] = s.name, [Object] = o.name, [Parameter] = p.name, [Data Type] = TYPE_NAME(p.user_type_id) + CASE WHEN p.system_type_id <> p.user_type_id THEN N' (' + TYPE_NAME(p.system_type_id) + N')' ELSE N'' END FROM sys.objects AS o INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] INNER JOIN sys.parameters AS p ON p.[object_id] = o.[object_id] WHERE p.system_type_id IN (34, 35, 99) ORDER BY [Schema], [Object], [Parameter];
出力:
すべてのデータベースでこのデータを返す必要がある場合は、sp_ineachdb
を取得できます。 、バグのある、文書化されていない、サポートされていないsp_MSforeachdb
の制限のいくつかを克服するために私が書いた(そしてこことここに文書化した)手順 。次に、これを行うことができます:
EXEC master.dbo.sp_ineachdb @command = N'SELECT [Database] = DB_NAME(), [Schema] = s.name, [Object] = o.name, [Column] = c.name, [Data Type] = TYPE_NAME(c.user_type_id) + CASE WHEN c.system_type_id <> c.user_type_id THEN N'' ('' + TYPE_NAME(c.system_type_id) + N'')'' ELSE N'''' END FROM sys.columns AS c INNER JOIN sys.objects AS o ON c.[object_id] = o.[object_id] INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] WHERE c.system_type_id IN (34, 35, 99) ORDER BY [Schema], [Object], [Column]; SELECT [Database] = DB_NAME(), [Schema] = s.name, [Object] = o.name, [Parameter] = p.name, [Data Type] = TYPE_NAME(p.user_type_id) + CASE WHEN p.system_type_id <> p.user_type_id THEN N'' ('' + TYPE_NAME(p.system_type_id) + N'')'' ELSE N'''' END FROM sys.objects AS o INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] INNER JOIN sys.parameters AS p ON p.[object_id] = o.[object_id] WHERE p.system_type_id IN (34, 35, 99) ORDER BY [Schema], [Object], [Parameter];';
ここで興味深い補足事項:すべてのデータベースに対してこれを実行すると、SQL Server 2019でも、Microsoftがこれらの古いタイプの一部を使用していることがわかります。
PowerShellまたはSQLServerの複数のインスタンスを管理するために使用する自動化ツールから実行することで、さらに自動化できます。
もちろん、これはほんの始まりに過ぎません。リストを作成するだけです。さらに拡張して、ALTER TABLE
のドラフトバージョンを生成することもできます。 コマンドはすべてのテーブルを更新する必要がありますが、それらのコマンドは実行する前に確認する必要があり、それでもプロシージャを自分で変更する必要があります(ALTER PROCEDURE
を生成する) これらのパラメータタイプ名のみが正しく置き換えられているコマンドは、決して簡単な演習ではありません)。 ALTER TABLE
を生成する例を次に示します。 コマンド、null可能性を考慮しますが、デフォルトの制約のような他の複雑さは考慮しません:
SELECT N'ALTER TABLE ' + QUOTENAME(s.name) + N'.' + QUOTENAME(o.name) + N' ALTER COLUMN ' + QUOTENAME(c.name) + N' ' + CASE c.system_type_id WHEN 34 THEN N'varbinary' WHEN 35 THEN N'varchar' WHEN 99 THEN N'nvarchar' END + N'(max)' + CASE c.is_nullable WHEN 0 THEN N' NOT' ELSE N'' END + N' NULL;' FROM sys.columns AS c INNER JOIN sys.objects AS o ON c.[object_id] = o.[object_id] INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] WHERE c.system_type_id IN (34, 35, 99);
出力:
ALTERTABLE[dbo]。[t2]ALTERCOLUMN [msg] nvarchar(max)NULL;
そして、不思議に思うかもしれませんが、いいえ、明示的なWITH (ONLINE = ON)
を使用してこの1回限りの操作を行うことはできません。 オプション:
列「msg」が現在サポートされていないデータ型(テキスト、ntext、画像、CLRタイプ、またはFILESTREAM。操作はオフラインで実行する必要があります。
結論
うまくいけば、これは、これらの非推奨のタイプを削除したい理由のいくつかの良い背景と、実際に変更を加えるための開始点を提供します。マイクロソフトは、製品から取り除ける機能があまりないという難しい方法を学びました。そのため、これらが私の生涯で実際に存在しなくなることを心配していません。しかし、除去の恐れがあなたの唯一の動機であってはなりません。