Database
 sql >> Baza danych >  >> RDS >> Database

Przestarzałe funkcje do wyjęcia z przybornika – część 3

Niedawno omówiłem kilka funkcji, których Microsoft odradza i o których, jak sądzę, również powinieneś zapomnieć. Był przypadek, w którym kolega stale promował przestarzały widok zgodności wstecznej sys.sysprocesses zamiast nowszych dynamicznych widoków zarządzania (DMV) i inny przypadek, w którym inny kolega usunął serwer produkcyjny za pomocą SQL Server Profiler.

Moje ostatnie spotkanie z rzeczami, o których najlepiej zapomnieć, to nowa procedura składowana z ntext parametr. Sprawdziłem i na pewno typ danych pasuje do schematu tabeli bazowej. Mój umysł zaczął ścigać się z tymi starszymi typami danych, aby wyjaśnić, dlaczego naprawdę nie powinniśmy ich już używać:

  • obraz
  • ntext
  • tekst

Typy te znajdują się na liście przestarzałych z wielu powodów i zajmują stałe miejsce na tej liście od czasu zastąpienia przez max w SQL Server 2005. Niektóre z tych problemów obejmują:

  • nie możesz używać wielu funkcji łańcuchowych, takich jak LEFT() , RTRIM() , UPPER() i większość operatorów porównania;
  • musisz użyć funkcji takich jak TEXTPTR , WRITETEXT i UPDATETEXT do modyfikacji;
  • nie możesz używać typów jako zmiennych lokalnych;
  • nie możesz odwoływać się do kolumn w DISTINCT , GROUP BY , ORDER BY , lub jako dołączona kolumna (nie, że powinieneś chcieć zrobić którekolwiek z tych);
  • mniejsze wartości, które mogą zmieścić się w wierszu, mogą to zrobić tylko z text in row opcja.

To nie jest wyczerpująca lista; istnieją inne różnice, które możesz uznać za mniej lub bardziej ważne. Dla mnie najbardziej palącym powodem jest to, że nie można odbudować indeksu klastrowego w trybie online, jeśli tabela zawiera jeden z tych typów danych.

Stwórzmy prostą bazę danych z kilkoma tabelami:

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

Teraz spróbujmy wykonać operacje online na stołach:

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

Podczas gdy pierwsza instrukcja się powiedzie, druga wyświetli komunikat o błędzie podobny do tego:

Komunikat 2725, poziom 16, stan 2
Nie można wykonać operacji online dla indeksu „PK__t2__3213E83FEEA1E0AD”, ponieważ indeks zawiera kolumnę „msg” typu danych tekst, ntext, obraz lub FILESTREAM. W przypadku indeksu nieklastrowego kolumna może być kolumną uwzględniania indeksu. W przypadku indeksu klastrowego kolumna może być dowolną kolumną tabeli. Jeśli użyto DROP_EXISTING, kolumna może być częścią nowego lub starego indeksu. Operacja musi być wykonana w trybie offline.

W jednorazowym scenariuszu komunikat o błędzie jest dość łatwy do pokonania:albo pomijasz tabelę, albo, jeśli tabela bezwzględnie musi zostać odbudowana, współpracujesz ze swoimi zespołami w celu zaplanowania przestoju. Kiedy automatyzujesz rozwiązanie do konserwacji indeksów lub wdrażasz nowe ustawienia kompresji w swoim środowisku, nieco bardziej kłopotliwe jest sprawienie, aby Twoje rozwiązanie obsługiwało obecny lub przyszły stan.

Co robić?

Możesz zacząć zastępować te kolumny ich bardziej nowoczesnymi odpowiednikami. Oto zapytanie, które pomoże Ci je wyśledzić za pomocą sys.columns widoku katalogu, ale jesteś zdany na wszelkie wyraźne odniesienia, które mogą istnieć w kodzie aplikacji:

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

Wyjście:

Może być kuszące, aby przejść do SSMS i ręcznie zmienić typy danych w tych kolumnach, ale mogą być też inne konsekwencje. Na przykład kolumny mogą mieć skojarzone z nimi domyślne ograniczenia. I możesz mieć procedury składowane z parametrami, które powinny być aktualizowane w tandemie:

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

Aby znaleźć wszystkie te przypadki, możesz dostosować powyższe zapytanie do wyszukiwania według sys.parameters widok katalogu zamiast:

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

Wyjście:

Jeśli chcesz zwrócić te dane we wszystkich bazach danych, możesz pobrać sp_ineachdb , procedura, którą napisałem (i udokumentowałem tutaj i tutaj), aby przezwyciężyć kilka ograniczeń w błędnym, nieudokumentowanym i nieobsługiwanym sp_MSforeachdb . Następnie możesz to zrobić:

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

Ciekawa uwaga dodatkowa:jeśli uruchomisz to we wszystkich bazach danych, odkryjesz, że nawet w SQL Server 2019 Microsoft nadal używa niektórych z tych starych typów.

Możesz dalej zautomatyzować to, uruchamiając go z PowerShell lub dowolnego narzędzia do automatyzacji, którego używasz do zarządzania wieloma instancjami SQL Server.

Oczywiście to dopiero początek – tworzy tylko listę. Możesz go dodatkowo rozszerzyć, aby wygenerować wersję roboczą ALTER TABLE polecenia, które należałoby zaktualizować wszystkie tabele, ale te polecenia musiałyby zostać przejrzane przed ich wykonaniem, a nadal trzeba by samemu zmodyfikować procedury (generując ALTER PROCEDURE polecenia, w których poprawnie zastąpiono tylko te nazwy typów parametrów, nie jest w żaden sposób łatwym ćwiczeniem). Oto przykład, który generuje ALTER TABLE poleceń, biorąc pod uwagę możliwość zerowania, ale bez innych komplikacji, takich jak domyślne ograniczenia:

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

Wyjście:

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

A jeśli się zastanawiasz, nie, nie możesz wykonać tej jednorazowej operacji z jawnym WITH (ONLINE = ON) opcja:

Msg 11427, poziom 16, stan 1
Nie można wykonać operacji online ALTER COLUMN dla tabeli „t2”, ponieważ kolumna „msg” ma obecnie lub jest zmieniana na nieobsługiwany typ danych:tekst, ntext, obraz, typ CLR lub STRUMIENIE PLIKÓW. Operacja musi być wykonana w trybie offline.

Wniosek

Mamy nadzieję, że zapewnia to dobre podstawy, dlaczego chcesz wyeliminować te przestarzałe typy, i punkt wyjścia do faktycznego wprowadzenia zmian. Microsoft przekonał się na własnej skórze, że nie ma zbyt wielu funkcji, które mogą po prostu wyrwać z produktu, więc nie martwię się, że kiedykolwiek przestaną one istnieć za mojego życia. Ale strach przed usunięciem nie powinien być Twoim jedynym motywatorem.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hekaton z niespodzianką:In-memory TVP – część 2

  2. Rodzaje poleceń SQL

  3. Twój kompletny przewodnik po złączach SQL:OUTER JOIN – część 2

  4. Pakiet hostingowy na Chocolatey

  5. Zalecenia dotyczące rutynowych kopii zapasowych treści