Database
 sql >> Datenbank >  >> RDS >> Database

Veraltete Funktionen, die Sie aus Ihrer Toolbox herausnehmen sollten – Teil 3

Ich habe kürzlich einige Funktionen besprochen, von denen Microsoft abrät und von denen Sie meiner Meinung nach auch vergessen sollten, dass sie existieren. Es gab den Fall, in dem ein Kollege ständig die veraltete Abwärtskompatibilitätsansicht sys.sysprocesses beworben hat anstelle neuerer dynamischer Verwaltungsansichten (DMVs) und ein weiterer Fall, in dem ein anderer Kollege einen Produktionsserver mit SQL Server Profiler heruntergefahren hat.

Meine letzte Begegnung mit Dingen, die man am besten vergisst, ist eine neue gespeicherte Prozedur mit einem ntext Parameter. Ich habe überprüft und tatsächlich stimmt der Datentyp mit dem Schema für die zugrunde liegende Tabelle überein. Meine Gedanken begannen über diese älteren Datentypen zu rasen, um zu erklären, warum wir sie wirklich nicht mehr verwenden sollten:

  • Bild
  • ntext
  • Text

Diese Typen stehen aus vielen Gründen auf der veralteten Liste und haben seit ihrer Ersetzung einen festen Platz auf dieser Liste eingenommen um das max Typen weit zurück in SQL Server 2005. Einige dieser Problempunkte sind:

  • Sie können nicht viele String-Funktionen verwenden, wie LEFT() , RTRIM() , UPPER() , und die meisten Vergleichsoperatoren;
  • Sie müssen Funktionen wie TEXTPTR verwenden , WRITETEXT , und UPDATETEXT für Änderungen;
  • Sie können die Typen nicht als lokale Variablen verwenden;
  • Sie können die Spalten in DISTINCT nicht referenzieren , GROUP BY , ORDER BY , oder als eingeschlossene Spalte (nicht, dass Sie dies tun sollten);
  • kleinere Werte, die in die Zeile passen könnten, können dies nur mit dem text in row tun Option.

Das ist keine erschöpfende Liste; Es gibt noch andere Unterschiede, die Sie für mehr oder weniger wichtig halten könnten. Der dringendste Grund für mich ist, dass Sie den Clustered-Index nicht online neu erstellen können, wenn die Tabelle einen dieser Datentypen enthält.

Lassen Sie uns eine einfache Datenbank mit ein paar Tabellen erstellen:

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);

Lassen Sie uns nun versuchen, Online-Operationen an den Tabellen durchzuführen:

ALTER TABLE dbo.t1 REBUILD WITH (ONLINE = ON);
GO
ALTER TABLE dbo.t2 REBUILD WITH (ONLINE = ON);

Während die erste Anweisung erfolgreich ist, liefert die zweite eine Fehlermeldung wie diese:

Msg 2725, Level 16, State 2
Für den Index „PK__t2__3213E83FEEA1E0AD“ kann kein Online-Vorgang durchgeführt werden, da der Index die Spalte „msg“ des Datentyps „text“, „ntext“, „image“ oder „FILESTREAM“ enthält. Bei einem nicht gruppierten Index könnte die Spalte eine Include-Spalte des Index sein. Bei einem gruppierten Index könnte die Spalte eine beliebige Spalte der Tabelle sein. Wenn DROP_EXISTING verwendet wird, könnte die Spalte Teil eines neuen oder alten Index sein. Der Vorgang muss offline durchgeführt werden.

In einem einmaligen Szenario ist die Fehlermeldung leicht zu handhaben:Sie überspringen entweder die Tabelle oder, wenn die Tabelle unbedingt neu erstellt werden muss, arbeiten Sie mit Ihren Teams zusammen, um einen Ausfall zu planen. Wenn Sie eine Indexwartungslösung automatisieren oder neue Komprimierungseinstellungen in Ihrer gesamten Umgebung bereitstellen, ist es ein bisschen mühsamer, Ihre Lösung mit dem aktuellen oder zukünftigen Status zurechtzukommen.

Was tun?

Sie können damit beginnen, diese Säulen durch ihre moderneren Gegenstücke zu ersetzen. Hier ist eine Abfrage, die Ihnen hilft, sie mithilfe von sys.columns aufzuspüren Katalogansicht, aber Sie sind allein für explizite Verweise, die möglicherweise in Ihrem Anwendungscode vorhanden sind:

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];

Ausgabe:

Es mag verlockend sein, in SSMS einzusteigen und die Datentypen dieser Spalten manuell zu ändern, aber es kann auch andere Auswirkungen haben. Beispielsweise können den Spalten Standardeinschränkungen zugeordnet sein. Und Sie haben möglicherweise gespeicherte Prozeduren mit Parametern, die gleichzeitig aktualisiert werden sollten:

CREATE PROCEDURE dbo.sp1 @p1 ntext AS PRINT 1;
GO

Um alle diese Fälle zu finden, können Sie die obige Abfrage so anpassen, dass sie nach sys.parameters sucht Katalogansicht stattdessen:

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];

Ausgabe:

Wenn Sie diese Daten über alle Datenbanken hinweg zurückgeben müssen, können Sie sich sp_ineachdb schnappen , ein Verfahren, das ich geschrieben (und hier und hier dokumentiert) habe, um einige der Einschränkungen in der fehlerhaften, undokumentierten und nicht unterstützten sp_MSforeachdb zu überwinden . Dann können Sie Folgendes tun:

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];';

Eine interessante Randnotiz hier:Wenn Sie das für alle Datenbanken ausführen, werden Sie feststellen, dass Microsoft selbst in SQL Server 2019 immer noch einige dieser alten Typen verwendet.

Sie könnten dies weiter automatisieren, indem Sie es über PowerShell oder ein beliebiges Automatisierungstool ausführen, das Sie zum Verwalten mehrerer Instanzen von SQL Server verwenden.

Das ist natürlich erst der Anfang – es ergibt nur eine Liste. Sie könnten es weiter erweitern, um eine Entwurfsversion der ALTER TABLE zu generieren Befehle müssten Sie alle Tabellen aktualisieren, aber diese Befehle müssten überprüft werden, bevor Sie sie ausführen, und Sie müssten die Prozeduren noch selbst ändern (durch Generieren von ALTER PROCEDURE Befehle, bei denen nur diese Parametertypnamen korrekt ersetzt werden, ist keineswegs eine einfache Übung). Hier ist ein Beispiel, das ALTER TABLE generiert Befehle unter Berücksichtigung der Nullfähigkeit, aber ohne andere Komplikationen wie Standardeinschränkungen:

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);

Ausgabe:

ALTER TABLE [dbo].[t2] ALTER COLUMN [msg] nvarchar(max) NULL;

Und falls Sie sich fragen, nein, Sie können diese einmalige Operation nicht mit einem expliziten WITH (ONLINE = ON) durchführen Möglichkeit:

Msg 11427, Level 16, State 1
Der Online-Vorgang ALTER COLUMN kann für die Tabelle „t2“ nicht ausgeführt werden, da die Spalte „msg“ derzeit einen nicht unterstützten Datentyp aufweist oder geändert wird:Text, ntext, Bild, CLR-Typ oder DATENFLUSS. Der Vorgang muss offline durchgeführt werden.

Schlussfolgerung

Hoffentlich bietet dies einen guten Hintergrund dafür, warum Sie diese veralteten Typen entfernen möchten, und einen Ausgangspunkt, um die Änderungen tatsächlich vorzunehmen. Microsoft hat auf die harte Tour gelernt, dass es nicht viele Funktionen gibt, die sie einfach aus dem Produkt herausreißen können, daher mache ich mir keine Sorgen, dass diese jemals zu meinen Lebzeiten aufhören werden. Aber die Angst vor der Entfernung sollte nicht Ihr einziger Motivator sein.