Nous sommes sur le point de manquer d'identifiants dans l'une des tables de notre OLTP Système de journalisation. C'est mon travail de trouver un moyen d'archiver les données de ligne existantes dans la table complète et dans tout Référifiez des tables afin que nous puissions continuer à enregistrer de nouvelles données dans les tables.
Le moyen le plus rapide pour nous d'archiver des données dans une table est simplement de renommer la table cible et de tous les objets dépendants - Tables de jonction, index, contraintes. C'est rapide et conserve les données intactes. Pour terminer le travail, nous devons créer de nouvelles copies vides de tous les objets avec leurs anciens noms. Si nous effectuons toutes ces opérations dans une transaction, les procédures stockées qui inséraient de nouvelles données ne manqueront pas à cause des tables manquantes.
J'ai mis ensemble un script PowerShell pour générer un script T-SQL pour effectuer l'opération d'archivage.
Le script ne génère pas autant de déclarations de renommée que cela devrait, et je ne comprends pas pourquoi.
Le script charge SMO, définit les noms des objets cibles et définit une connexion de capture uniquement sur le serveur - ceci permet de capturer des commandes de renommée pour inspection ultérieure:
Add-Type -AssemblyName "Microsoft.SqlServer.Smo, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91";
$ServerName = 'CLOUDCORP\LOGGING'
$DatabaseName = 'Logging'
$TableName = 'tbDataRequests'
$TableSchemaName = 'Logging'
$Server = New-Object Microsoft.SqlServer.Management.Smo.Server $ServerName
$Server.ConnectionContext.SqlExecutionModes = [Microsoft.SqlServer.Management.Common.SqlExecutionModes]::CaptureSql
Ensuite, il crée une gamme d'objets qui vont être archivés en renommant. La table cible elle-même, toutes les tables de référencement et toutes les clés et tous les index de ces tables doivent être archivés:
$Database = $Server.Databases[$DatabaseName]
$Table = @($Database.Tables[$TableName, $TableSchemaName])
$ReferencingTables = $Database.Tables.ForeignKeys |
? { $_.ReferencedTable -eq $TableName -and $_.ReferencedTableSchema -eq $TableSchemaName } |
% { $_.Parent } | Sort ID | Get-Unique
$TablesToArchive = $Table + $ReferencingTables
$ObjectsToArchive = $TablesToArchive + $TablesToArchive.Indexes + $TablesToArchive.ForeignKeys
La partie problématique est la suivante. Pour chaque objet d'archiver, j'essaie de capturer une déclaration de renommée.
$ObjectsToArchive | % { $_.Rename($_.Name + '_archive') }
$RenameCommands = $Server.ConnectionContext.CapturedSql.Text
Après avoir exécuté cela contre ma base de données, le tableau $ObjectsToArchive
contient 48 articles. L'expression $objectsToArchive.Name
Produit une liste comme celle-ci:
tbDataRequests
tbDataRequestPenguinServers
tbDataRequestLegs
tbDataRequestPaidDataRequests
tbDataRequestResponses
tbDataRequestUUIDMappings
tbDataRequestRouteNodes
tbRequestDataRequestQ
tbRequestDataRequests
IX_DataRequests_DataRequestDT
PK_DataRequests
PK_DataRequestPenguinServers
PK_DataRequestLegs
IX_DataRequestPaidDataRequests_PaidDataRequestID
PK_DataRequestPaidDataRequests
IX_DataRequestResponses_ScrapeResponseID
PK_DataRequestResponses
IX_DataRequestUUIDMappings_DataRequestID
PK_DataRequestUUIDMappings
PK_Geo_DataRequestRouteNodes
IX_RequestDataRequestQ_FK_RequestUUIDID
PK_RequestDataRequestQ
IX_RequestDataRequests_DataRequestID
PK_RequestDataRequests
FK_DataRequests_OrderType_OrderTypeID
FK_DataRequests_DatePairs_DatePairID
FK_DataRequests_CustomerCounts_CustomerCountID
FK_DataRequests_Routes_RouteID
FK_DataRequests_DataClients_DataClientID
FK_DataRequests_UserCountries_UserCountryID
FK_DataRequests_Websites_WebsiteID
FK_DataRequestPenguinServers_PenguinServers_JacqiardServerID
FK_DataRequestPenguinServers_DataRequests_DataRequestID
FK_DataRequestLegs_DatePairs_DatePairID
FK_DataRequestLegs_LegTypes_LegTypeID
FK_DataRequestLegs_Routes_RouteID
FK_DataRequestLegs_DataRequests_DataRequestID
FK_DataRequestPaidDataRequests_PaidDataRequests_PaidDataRequestID
FK_DataRequestPaidDataRequests_DataRequests_DataRequestID
FK_DataRequestResponses_DataRequests_DataRequestID
FK_DataRequestResponses_ScrapeResponses_ScrapeResponseID
FK_DataRequestUUIDMappings_DataRequests_DataRequestID
FK_DataRequestUUIDMappings_DataRequestUUIDs_Scrape RequestUUIDID
FK_Geo_DataRequestRouteNodes_DataRequests_DataRequestID
FK_RequestDataRequestQ_RequestUUIDs_RequestUUIDID
FK_RequestDataRequestQ_DataRequests_DataRequestID
FK_RequestDataRequests_Requests_RequestID
FK_RequestDataRequests_DataRequests_RequestID
Il devrait y avoir une déclaration de renommée pour chaque objet de cette matrice. Cependant, la propriété CaptureSQL ne contient que 10 déclarations de renommée. L'expression $RenameCommands | ? { $_ -like '*sp_rename*' }
Produit une liste comme celle-ci:
EXEC dbo.sp_rename @objname = N'[Logging].[tbDataRequests]', @newname = N'tbDataRequests_archive', @objtype = N'OBJECT'
EXEC sp_rename N'[Logging].[tbDataRequests].[IX_DataRequests_DataRequestDT]', N'IX_DataRequests_DataRequestDT_archive', N'INDEX'
EXEC sp_rename N'[Logging].[tbDataRequests].[PK_DataRequests]', N'PK_DataRequests_archive', N'INDEX'
EXEC sp_rename N'[FK_DataRequests_OrderType_OrderTypeID]', N'FK_DataRequests_OrderType_OrderTypeID_archive', N'OBJECT'
EXEC sp_rename N'[FK_DataRequests_DatePairs_DatePairID]', N'FK_DataRequests_DatePairs_DatePairID_archive', N'OBJECT'
EXEC sp_rename N'[FK_DataRequests_CustomerCounts_CustomerCountID]', N'FK_DataRequests_CustomerCounts_CustomerCountID_archive', N'OBJECT'
EXEC sp_rename N'[FK_DataRequests_Routes_RouteID]', N'FK_DataRequests_Routes_RouteID_archive', N'OBJECT'
EXEC sp_rename N'[FK_DataRequests_DataClients_DataClientID]', N'FK_DataRequests_DataClients_DataClientID_archive', N'OBJECT'
EXEC sp_rename N'[FK_DataRequests_UserCountries_UserCountryID]', N'FK_DataRequests_UserCountries_UserCountryID_archive', N'OBJECT'
EXEC sp_rename N'[FK_DataRequests_Websites_WebsiteID]', N'FK_DataRequests_Websites_WebsiteID_archive', N'OBJECT'
Il est en train de renommer des instructions pour la journalisation .TbdatariAquests et ses clés et ses index, mais pas pour aucun des autres objets.
Qu'est-ce que je fais mal ici?
Vous ne pouvez pas boucler à travers des objets de la manière dont vous avez codé. Voici le code de travail:
Add-Type -AssemblyName "Microsoft.SqlServer.Smo, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91";
$ServerName = 'xyzabc123'
$DatabaseName = 'test1'
$TableName = 'main'
$TableSchemaName = 'dbo'
$Server = New-Object Microsoft.SqlServer.Management.Smo.Server $ServerName
$Server.ConnectionContext.SqlExecutionModes = [Microsoft.SqlServer.Management.Common.SqlExecutionModes]::CaptureSql
$Database = $Server.Databases[$DatabaseName]
$Table = $Database.Tables[$TableName, $TableSchemaName]
$TablesToArchive = @($Table)
$Database.Tables | Select -ExpandProperty ForeignKeys | % {
if($_.ReferencedTable -eq $TableName -and $_.ReferencedTableSchema -eq $TableSchemaName)
{ $TablesToArchive += $_.Parent }
}
# $TablesToArchive | % { $_.Name }
$ObjectsToArchive = ($TablesToArchive | Select -ExpandProperty Indexes) + ($TablesToArchive | Select -ExpandProperty ForeignKeys)
# $ObjectsToArchive | % { $_.Name }
$ObjectsToArchive | % {
$_.Rename($_.Name + '_archive')
}
$RenameCommands = $Server.ConnectionContext.CapturedSql.Text
# $RenameCommands
Par exemple, vous vous attendiez
$Database.Tables.ForeignKeys
Pour vous donner une collection combinée ForeignKeys
composé de ForeignKeys
de chaque objet Tables
objet. Si vous avez ajouté les commandes de débogage
# $ObjectsToArchive | % { $_.Name }
Vous auriez pu la suivre très rapidement.