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