Database
 sql >> база данни >  >> RDS >> Database

Оттеглени функции, които да извадите от кутията си с инструменти – част 3

Наскоро обсъдих няколко функции, които Microsoft съветва да не използвате и които мисля, че трябва да забравите, че съществуват. Имаше случай, когато колега непрекъснато популяризира отхвърления изглед за обратна съвместимост sys.sysprocesses вместо по-нови динамични изгледи за управление (DMV) и друг случай, при който различен колега свали производствен сървър с помощта на SQL Server Profiler.

Последното ми сблъскване с нещата, които най-добре са забравени, е нова съхранена процедура с ntext параметър. Проверих и, разбира се, типът данни съвпада със схемата за основната таблица. Умът ми започна да се надпреварва за тези по-стари типове данни, за да обясня защо наистина не трябва да ги използваме повече:

  • изображение
  • ntext
  • текст

Тези типове са в оттеглилия списък по много причини и заемат постоянно място в този списък откакто са заменени чрез max типове още в SQL Server 2005. Някои от тези болезнени точки включват:

  • не можете да използвате много низови функции, като 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);

Докато първият оператор е успешен, вторият дава съобщение за грешка като това:

Msg 2725, ниво 16, състояние 2
Онлайн операция не може да бъде извършена за индекс 'PK__t2__3213E83FEEA1E0AD', тъй като индексът съдържа колона 'msg' с тип данни текст, ntext, изображение или FILESTREAM. За неклъстериран индекс колоната може да бъде колона за включване на индекса. За клъстериран индекс колоната може да бъде всяка колона на таблицата. Ако се използва DROP_EXISTING, колоната може да бъде част от нов или стар индекс. Операцията трябва да се извърши офлайн.

При еднократен сценарий съобщението за грешка е достатъчно лесно за справяне:или пропускате масата, или, ако масата абсолютно трябва да бъде преустроена, работите с вашите екипи, за да планирате прекъсване. Когато автоматизирате решение за поддръжка на индекси или внедрявате нови настройки за компресиране във вашата среда, е малко по-трудно да накарате решението ви да обработва настоящо или бъдещо състояние.

Какво да правя?

Можете да започнете да заменяте тези колони с техните по-модерни колеги. Ето заявка, която да ви помогне да ги проследите с помощта на 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 или какъвто и да е инструмент за автоматизация, който използвате, за да управлявате множество копия на SQL Server.

Разбира се, това е само началото – създава само списък. Можете допълнително да го разширите, за да генерирате чернова версия на ALTER TABLE команди, които ще трябва да актуализирате всички таблици, но тези команди ще трябва да бъдат прегледани, преди да ги изпълните, и все пак ще трябва сами да промените процедурите (генериране на ALTER PROCEDURE команди, които имат само тези имена на типове параметри, заменени правилно, по никакъв начин не е лесно упражнение). Ето един пример, който генерира ALTER TABLE команди, като се отчита възможността за нула, но без други усложнения като ограничения по подразбиране:

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

Изход:

ПРОМЕНИ ТАБЛИЦА [dbo].[t2] ПРОМЕНИ КОЛОНА [msg] nvarchar(max) NULL;

И в случай, че се чудите, не, не можете да извършите тази еднократна операция с изричен WITH (ONLINE = ON) опция:

Msg 11427, ниво 16, състояние 1
Операцията ALTER COLUMN не може да се извърши за таблица 't2', тъй като колоната 'msg' в момента има или се променя в неподдържан тип данни:текст, ntext, изображение, тип CLR или ФАЙЛОВ ПОТОК. Операцията трябва да се извърши офлайн.

Заключение

Надяваме се, че това предоставя добра информация защо искате да премахнете тези отхвърлени типове и отправна точка, за да направите промените. Microsoft научи по трудния начин, че няма много функции, които могат просто да извадят от продукта, така че не се притеснявам, че те някога ще престанат да съществуват през живота ми. Но страхът от отстраняване не трябва да е единственият ви мотиватор.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Подобрете производителността на UDF с NULL НА NULL INPUT

  2. Превеждане на данни на Salesforce във формат EDI

  3. Какво представлява технологията JPA на Java?

  4. Прозрачно криптиране на данни и винаги криптирани

  5. Друга причина да избягвате sp_updatestats