Процесс изменения размера столбцов SQL Server для столбцов VARCHAR / NVARCHAR - PullRequest
0 голосов
/ 16 марта 2012

Я притворяюсь администратором базы данных, поскольку у нашей компании его нет - изначально наши серверы были настроены на разные типы сортировки, а первоначальный разработчик T-SQL написал курсор, который будет циклически проходить по всем таблицам с * 1001. * столбцы и стандартизировать параметры сортировки ... благодаря их методологии это в конечном итоге увеличило размер этих столбцов до максимального значения, поскольку у него не было элементов управления для проверки таблиц, которые УЖЕ были обновлены.

Нам крайне необходимо иметь возможность правильно индексировать и настраивать производительность в этих таблицах, так как наш анализ буквально требует ЧАСОВ для завершения, что, конечно, становится проблемой для полей, для которых все настроены на некоторое изменение varchar/nvarchar (max/4000/8000).

Сегодня вечером я работаю с нашим сетевым / ИТ-специалистом над восстановлением базы данных MASTER на рассматриваемом сервере. Я написал следующий код для изменения размера столбцов после окончательного сопоставления. ПОЖАЛУЙСТА, оцените и дайте мне некоторую обратную связь на случай, если я что-то пропустил и в конечном итоге получу головную боль, исправляя ошибки (мы, конечно, сначала сделаем полное резервное копирование всего).

Мы не должны поддерживать сервер и БД в оперативном режиме для этого процесса и можем позволить себе определенное время простоя для завершения.

SELECT  obj.name as Table_Name, clm.name as Column_Name
, case when clm.system_type_ID = 167 then 'varchar' else 'nvarchar' end as Column_Type
, cast(0 as int) as Column_Length
INTO    #tmp_Table_Column_Types
FROM    sys.objects as obj
LEFT OUTER JOIN sys.columns as clm
ON      clm.object_id = obj.object_id
LEFT OUTER JOIN sys.dm_db_partition_stats as dbp
ON      dbp.object_id = obj.object_id
WHERE   obj.type_desc in ('USER_TABLE')
AND     clm.system_type_ID in (167,231)
AND     dbp.Row_Count > 0

DECLARE @Table_Name nvarchar(500)
    ,   @Column_Name nvarchar(500)
    ,   @Column_Type varchar(8)
    ,   @Column_Length int
    ,   @SQL nvarchar(4000)

DECLARE TTCLU CURSOR FOR -- Temporary Table Column Length Update

SELECT Table_Name, Column_Name
FROM    #tmp_Table_Column_Types

OPEN ttclu

FETCH next FROM TTCLU INTO
@Table_Name, @Column_Name

WHILE @@Fetch_Status = 0

BEGIN

SET @SQL = '
UPDATE tmp SET Column_Length = sub.max_length
FROM  #tmp_Table_Column_Types AS tmp
LEFT OUTER JOIN (
SELECT  case when max(len('+@Column_Name+')) <= 5 then 5
        when max(len('+@Column_Name+')) > 5 and max(len('+@Column_Name+')) <= 10 then 10
        when max(len('+@Column_Name+')) > 10 and max(len('+@Column_Name+')) <= 15 then 15
        when max(len('+@Column_Name+')) > 15 and max(len('+@Column_Name+')) <= 25 then 25
        when max(len('+@Column_Name+')) > 25 and max(len('+@Column_Name+')) <= 50 then 50
        when max(len('+@Column_Name+')) > 50 and max(len('+@Column_Name+')) <= 75 then 75
        when max(len('+@Column_Name+')) > 75 and max(len('+@Column_Name+')) <= 100 then 100
        when max(len('+@Column_Name+')) > 100 and max(len('+@Column_Name+')) <= 150 then 150
        when max(len('+@Column_Name+')) > 150 and max(len('+@Column_Name+')) <= 200 then 200
        when max(len('+@Column_Name+')) > 200 and max(len('+@Column_Name+')) <= 500 then 500
        when max(len('+@Column_Name+')) > 500 or max(len('+@Column_Name+')) is null then 1000
        end as Max_Length
FROM    '+@Table_Name+'
) AS sub
ON      ''A'' = ''A''
WHERE   tmp.Table_Name = '''+@Table_Name+'''
AND     tmp.Column_Name = '''+@Column_Name+'''
' print @sql execute sp_executesql @sql

FETCH next FROM TTCLU INTO
@Table_Name, @Column_Name

END

CLOSE TTCLU
DEALLOCATE TTCLU


DECLARE ATCT CURSOR FOR     -- Alter Table Column Type

SELECT *
FROM #tmp_Table_Column_Types

OPEN ATCT

FETCH next FROM ATCT INTO
@Table_Name, @Column_Name, @Column_Type, @Column_Length

WHILE @@Fetch_Status = 0

BEGIN

SET @SQL = '
ALTER TABLE '+@Table_Name+' ALTER COLUMN '+@Column_Name+' '+@Column_Type+' ('+cast(@Column_Length as nvarchar)+')
' print @sql execute sp_executesql @sql

FETCH next FROM ATCT INTO
@Table_Name, @Column_Name, @Column_Type, @Column_Length

END

CLOSE ATCT
DEALLOCATE ATCT

ОСНОВНОЕ РЕДАКТИРОВАНИЕ: Приведенный выше код является хорошим началом для решения моей проблемы: ОДНАКО - Определение максимальной длины данных из столбцов sys.columns НЕ 100% точно. Чтобы доказать это, запустите первые два курсора, как показано, затем

SELECT * FROM #tmp_Table_Column_Types ORDER BY Column_Length

Вы увидите некоторые длины столбцов, перечисленные как 0 (и, возможно, несколько, длина которых меньше 10 символов, которые вы можете быть довольно подозрительными).

Если вы сделаете запрос на выборку в указанной таблице и упорядочите его по лен (поле), вы увидите, что в столбцах предполагаемой длины 0 действительно есть данные IS.

Я пока не нашел элегантного решения для этого, однако вместо этого я использую подзапрос, чтобы провести фактический опрос данных столбца и вернуть длину.

...