sql >> Database teknologi >  >> RDS >> Database

Forældede funktioner til at tage ud af din værktøjskasse – Del 3

Jeg har for nylig diskuteret et par funktioner, som Microsoft fraråder at bruge, og som jeg synes, du også bør glemme, at eksisterer. Der var et tilfælde, hvor en kollega konstant promoverede den forældede bagudkompatibilitetsvisning sys.sysprocesses i stedet for nyere dynamiske administrationsvisninger (DMV'er) og et andet tilfælde, hvor en anden kollega fjernede en produktionsserver ved hjælp af SQL Server Profiler.

Min seneste indkøring med ting, der bedst er glemt, er en ny lagret procedure med en ntext parameter. Jeg tjekkede, og helt sikkert matcher datatypen skemaet for den underliggende tabel. Mit sind begyndte at rase om disse ældre datatyper for at forklare, hvorfor vi virkelig ikke skulle bruge dem længere:

  • billede
  • ntekst
  • tekst

Disse typer er på den forældede liste af mange årsager og har haft en permanent plads på listen, siden de blev erstattet med max typer langt tilbage i SQL Server 2005. Nogle af disse smertepunkter omfatter:

  • du kan ikke bruge mange strengfunktioner, såsom LEFT() , RTRIM() , UPPER() , og de fleste sammenligningsoperatører;
  • du skal bruge funktioner som TEXTPTR , WRITETEXT , og UPDATETEXT til ændringer;
  • du kan ikke bruge typerne som lokale variabler;
  • du kan ikke henvise til kolonnerne i DISTINCT , GROUP BY , ORDER BY , eller som en inkluderet kolonne (ikke at du skulle ønske at gøre nogen af ​​disse);
  • mindre værdier, der kunne passe i rækken, kan kun gøre det med text in row mulighed.

Det er ikke en udtømmende liste; der er andre forskelle, som du måske betragter som mere eller mindre vigtige. Den mest presserende grund for mig er, at du ikke kan genopbygge det klyngede indeks online, hvis tabellen indeholder en af ​​disse datatyper.

Lad os oprette en simpel database med nogle få tabeller:

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

Lad os nu prøve at udføre online operationer på bordene:

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

Mens den første sætning lykkes, giver den anden en fejlmeddelelse som denne:

Msg 2725, Level 16, State 2
En online-handling kan ikke udføres for indeks 'PK__t2__3213E83FEEA1E0AD', fordi indekset indeholder kolonne 'msg' af datatypen tekst, ntext, image eller FILESTREAM. For et ikke-klynget indeks kan kolonnen være en inkluderende kolonne i indekset. For et klynget indeks kan kolonnen være en hvilken som helst kolonne i tabellen. Hvis DROP_EXISTING bruges, kan kolonnen være en del af et nyt eller gammelt indeks. Handlingen skal udføres offline.

I et enkeltstående scenarie er fejlmeddelelsen let nok at håndtere:enten springer du bordet over, eller hvis bordet absolut skal genopbygges, arbejder du sammen med dine teams for at planlægge en udfald. Når du automatiserer en indeksvedligeholdelsesløsning eller implementerer nye kompressionsindstillinger på tværs af dit miljø, er det en smule mere smertefuldt at få din løsning til at håndtere nuværende eller fremtidige tilstand.

Hvad skal man gøre?

Du kan begynde at erstatte disse søjler med deres mere moderne modstykker. Her er en forespørgsel, der hjælper dig med at spore dem ved hjælp af sys.columns katalogvisning, men du er på egen hånd for alle eksplicitte referencer, der måtte findes i din ansøgningskode:

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

Output:

Det kan være fristende at gå ind i SSMS og manuelt ændre datatyperne for disse kolonner, men der kan også være andre implikationer. For eksempel kan kolonnerne have standardbegrænsninger knyttet til dem. Og du har muligvis gemte procedurer med parametre, der bør opdateres i tandem:

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

For at finde alle disse tilfælde kan du tilpasse ovenstående forespørgsel til at søge mod sys.parameters katalogvisning i stedet:

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

Output:

Hvis du har brug for at returnere disse data på tværs af alle databaser, kan du få fat i sp_ineachdb , en procedure jeg skrev (og dokumenterede her og her) for at overvinde flere af begrænsningerne i buggyen, udokumenterede og ikke-understøttede sp_MSforeachdb . Så kan du gøre dette:

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

En interessant sidebemærkning her:Hvis du kører det mod alle databaser, vil du opdage, at selv i SQL Server 2019 bruger Microsoft stadig nogle af disse gamle typer.

Du kan yderligere automatisere det ved at køre det fra PowerShell eller et hvilket som helst automatiseringsværktøj, du bruger til at administrere flere forekomster af SQL Server.

Det er selvfølgelig kun begyndelsen – det producerer kun en liste. Du kan udvide det yderligere til at generere en udkast til version af ALTER TABLE kommandoer, du skal bruge for at opdatere alle tabellerne, men disse kommandoer skal gennemgås, før du udfører dem, og du skal stadig selv ændre procedurerne (generering af ALTER PROCEDURE kommandoer, der kun har disse parametertypenavne erstattet korrekt, er på ingen måde en nem øvelse). Her er et eksempel, der genererer ALTER TABLE kommandoer, der tager hensyn til nullabilitet, men ingen andre komplikationer som standardbegrænsninger:

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

Output:

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

Og hvis du undrer dig, nej, du kan ikke udføre denne engangsoperation med en eksplicit WITH (ONLINE = ON) mulighed:

Msg 11427, Level 16, State 1
Online ALTER COLUMN-operationen kan ikke udføres for tabel 't2', fordi kolonnen 'msg' i øjeblikket har eller bliver ændret til en ikke-understøttet datatype:tekst, ntext, billede, CLR-type eller FILESTREAM. Handlingen skal udføres offline.

Konklusion

Forhåbentlig giver dette en god baggrund for, hvorfor du ønsker at fjerne disse forældede typer, og et udgangspunkt for rent faktisk at foretage ændringerne. Microsoft lærte på den hårde måde, at der ikke er meget funktionalitet, de bare kan rive ud af produktet, så jeg er ikke bekymret for, at disse nogensinde faktisk vil ophøre med at eksistere i min levetid. Men frygt for fjernelse bør ikke være din eneste motivator.


  1. PostgreSQL:Forespørgsel har ingen destination for resultatdata

  2. Tuning Input/Output (I/O) operationer for PostgreSQL

  3. Udskiftning af tabelpartitioner i SQL Server:En gennemgang

  4. Korrekt måde at bruge LIKE '%{$var}%' med forberedte udsagn? [mysqli]