sql >> Database >  >> RDS >> Database

Verouderde functies om uit uw gereedschapskist te halen - Deel 3

Ik heb onlangs een paar functies besproken die Microsoft afraadt te gebruiken, en waarvan ik denk dat je ze ook moet vergeten. Er was een geval waarbij een collega constant de verouderde achterwaartse compatibiliteitsweergave promootte sys.sysprocesses in plaats van nieuwere dynamische beheerweergaven (DMV's), en een ander geval waarbij een andere collega een productieserver uitschakelde met behulp van SQL Server Profiler.

Mijn laatste aanloop met dingen die je het beste kunt vergeten, is een nieuwe opgeslagen procedure met een ntext parameter. Ik heb het gecontroleerd en, ja hoor, het gegevenstype komt overeen met het schema voor de onderliggende tabel. Mijn geest begon te racen over deze oudere gegevenstypen om uit te leggen waarom we ze echt niet meer zouden moeten gebruiken:

  • afbeelding
  • ntext
  • tekst

Deze typen staan ​​om vele redenen op de verouderde lijst en hebben sinds hun vervanging een vaste plek op die lijst ingenomen door de max typen in SQL Server 2005. Enkele van deze pijnpunten zijn:

  • u kunt niet veel tekenreeksfuncties gebruiken, zoals LEFT() , RTRIM() , UPPER() , en de meeste vergelijkingsoperatoren;
  • je moet functies gebruiken zoals TEXTPTR , WRITETEXT , en UPDATETEXT voor wijzigingen;
  • je kunt de typen niet als lokale variabelen gebruiken;
  • je kunt niet verwijzen naar de kolommen in DISTINCT , GROUP BY , ORDER BY , of als een opgenomen kolom (niet dat u een van deze zou willen doen);
  • kleinere waarden die in de rij zouden kunnen passen, kunnen dit alleen met de text in row optie.

Dat is geen uitputtende lijst; er zijn andere verschillen die u misschien meer of minder belangrijk vindt. De meest dringende reden voor mij is dat je de geclusterde index niet online kunt herbouwen als de tabel een van deze gegevenstypen bevat.

Laten we een eenvoudige database maken met een paar tabellen:

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

Laten we nu proberen om online bewerkingen uit te voeren op de tafels:

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

Terwijl de eerste instructie slaagt, levert de tweede een foutmelding op zoals deze:

Msg 2725, Level 16, State 2
Er kan geen online bewerking worden uitgevoerd voor index 'PK__t2__3213E83FEEA1E0AD' omdat de index kolom 'msg' van het gegevenstype text, ntext, image of FILESTREAM bevat. Voor een niet-geclusterde index kan de kolom een ​​include-kolom van de index zijn. Voor een geclusterde index kan de kolom elke kolom van de tabel zijn. Als DROP_EXISTING wordt gebruikt, kan de kolom deel uitmaken van een nieuwe of oude index. De bewerking moet offline worden uitgevoerd.

In een eenmalig scenario is de foutmelding eenvoudig genoeg om op te lossen:u slaat de tafel over of, als de tafel absoluut opnieuw moet worden opgebouwd, werkt u samen met uw teams om een ​​storing te plannen. Wanneer u een oplossing voor indexonderhoud automatiseert of nieuwe compressie-instellingen in uw omgeving implementeert, is het een beetje lastiger om uw oplossing de huidige of toekomstige status te laten verwerken.

Wat te doen?

U kunt deze kolommen gaan vervangen door hun modernere tegenhangers. Hier is een zoekopdracht om u te helpen ze op te sporen met behulp van de sys.columns catalogusweergave, maar u staat er alleen voor om eventuele expliciete verwijzingen in uw applicatiecode te vinden:

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

Uitgang:

Het kan verleidelijk zijn om naar SSMS te gaan en de gegevenstypen van deze kolommen handmatig te wijzigen, maar er kunnen ook andere implicaties zijn. Aan de kolommen kunnen bijvoorbeeld standaardbeperkingen zijn gekoppeld. En je hebt misschien opgeslagen procedures met parameters die tegelijk moeten worden bijgewerkt:

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

Om al deze gevallen te vinden, kunt u de bovenstaande zoekopdracht aanpassen om te zoeken op de sys.parameters catalogusweergave in plaats daarvan:

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

Uitgang:

Als u deze gegevens in alle databases moet retourneren, kunt u sp_ineachdb pakken , een procedure die ik heb geschreven (en hier en hier gedocumenteerd) om verschillende van de beperkingen in de buggy, ongedocumenteerde en niet-ondersteunde sp_MSforeachdb te omzeilen . Dan kun je dit doen:

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

Een interessante kanttekening hierbij:als je dat op alle databases uitvoert, zul je ontdekken dat, zelfs in SQL Server 2019, Microsoft nog steeds enkele van deze oude typen gebruikt.

Je zou dat verder kunnen automatiseren door het uit te voeren vanuit PowerShell of welke automatiseringstool je ook gebruikt om meerdere exemplaren van SQL Server te beheren.

Dat is natuurlijk nog maar het begin - het levert alleen een lijst op. Je zou het verder kunnen uitbreiden om een ​​conceptversie te genereren van de ALTER TABLE commando's zou je alle tabellen moeten bijwerken, maar die commando's zouden moeten worden beoordeeld voordat je ze uitvoert, en je zou nog steeds de procedures zelf moeten wijzigen (genereren van ALTER PROCEDURE commando's waarbij alleen die parametertypenamen correct zijn vervangen, is op geen enkele manier een gemakkelijke oefening). Hier is een voorbeeld dat ALTER TABLE genereert commando's, rekening houdend met nullabiliteit maar geen andere complicaties zoals standaardbeperkingen:

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

Uitgang:

WIJZIG TABEL [dbo].[t2] WIJZIG KOLOM [msg] nvarchar(max) NULL;

En voor het geval je je afvraagt, nee, je kunt deze eenmalige handeling niet doen met een expliciete WITH (ONLINE = ON) optie:

Msg 11427, Level 16, State 1
De online ALTER COLUMN-bewerking kan niet worden uitgevoerd voor tabel 't2' omdat kolom 'msg' momenteel een niet-ondersteund gegevenstype heeft of wordt gewijzigd:tekst, ntext, afbeelding, CLR-type of BESTANDSSTROOM. De bewerking moet offline worden uitgevoerd.

Conclusie

Hopelijk biedt dit een goede achtergrond over waarom u deze verouderde typen wilt elimineren, en een startpunt om de wijzigingen daadwerkelijk aan te brengen. Microsoft heeft op de harde manier geleerd dat er niet veel functionaliteit is die ze zomaar uit het product kunnen halen, dus ik maak me geen zorgen dat deze ooit in mijn leven zullen ophouden te bestaan. Maar angst voor verwijdering zou niet je enige motivator moeten zijn.


  1. Emulator versus Samsung-apparaat SD-kaartopslag

  2. Analyseer Big Data met Microsoft Azure Tools

  3. RAC-volgordeconflict

  4. Gegevens invoegen in een MySQL-database