【问题标题】:Migration from TFS to VSTS - Action Required on dbo.tbl_Content从 TFS 迁移到 VSTS - 需要对 dbo.tbl_Content 执行操作
【发布时间】:2021-03-26 00:46:02
【问题描述】:

我们计划很快从本地 TFS 迁移到 VSTS。在迁移之前,我已经运行了先决条件验证任务并获得了当前 TPC 数据库大小超出最大 DacPac 限制的警告。

下面提供了数据库验证的 sn-p:

The full database size is       187411 MB.
The database metadata  size is   28145 MB.
The database blob size is       159266 MB.
The top 10 largest tables are:

===================================================
Table name                               Size in MB
dbo.tbl_Content                          168583
dbo.tbl_BuildInformation2                3233

===================================================
The File owners are:
===================================================
Owner                                    Size in MB
Build+Git                                67410
TeamTest                                 59261
VersionControl                           18637

从上面很明显,dbo.tbl_Content 表是造成数据库大小过大的主要原因,从 VSTS 操作的角度来看,Build+Git 和 TeamTest 是罪魁祸首。因此,我的意图是专注于上述对象,以便清理任何数据库以减小大小。

问题是,我怎样才能以最有效和最好的方式在上述三个对象 - dbo.tbl_Content、Build+Git 和 TeamTest 上实现这一点?

【问题讨论】:

标签: git tfs azure-devops


【解决方案1】:

我写了一篇关于在导入前清理 TFS 的所有方法的详细文章:

但请记住,有一条备用路径需要在 Azure 中安装临时 IaaS 服务器,并在其上安装 SQL Server 和 TFS/Azure DevOps Server。这条路径可能比尝试清理你拥有的东西更简单、更快捷。


摘录如下:

要为迁移准备 TFS 项目集合,您可能需要先删除(陈旧的)旧数据以减小数据库大小。

大多数操作已在此处记录。可以帮助检测您的空间分配位置的查询也可以在最近的支持票中找到。

删除旧工作区

删除工作区和搁置集可以大大减少迁移和升级时间。使用 tf 命令行或利用 TFS SideKicks 之类的工具来识别和删除这些。

构建结果

不仅是构建结果,而且经常被忽略的实际构建记录可能会占用大量数据。使用 tfsbuild destroy (XAML) 永久删除构建记录。过去,我遇到过在他们的数据库中有 180 万个“隐藏”构建的客户,并且删除它们会刮掉相当多的数据。这些记录保存在仓库周围。

如果您遇到 tfsbuild 执行速度非常慢,you may need this patched version it has a few fixes that prevent it from trying to download all the build logs 为您系统中的每个构建,只是为了获取构建 ID。

旧团队项目

当然,销毁旧的团队项目可以回馈大量数据。您不需要发送到 azure 的任何内容都会有所帮助。您还可以考虑拆分集合并留下旧项目。如果您再次需要该数据,您可以选择分离该集合并将其存储在某个地方。

冗余文件

删除的分支是一种非常常见的隐藏大小猪。在 TFVC 中删除东西时,它们实际上并没有被删除,它们只是被隐藏了。查找已删除的文件,尤其是旧的开发或功能分支可以为您提供大量数据。使用tf destroy 摆脱它们。

您可能还想查找已签入的 nuget 包文件夹,这些文件夹也会很快占用大量空间。

代码镜头索引

Team Foundation Server 2013 引入了 TFVC 控制文件的服务器端索引,以允许 Visual Studio 直接在 UI 中访问有关谁更改了哪些文件的数据。这个服务器端索引可以根据您的代码库的大小和流失率快速增长。

您可以通过tfsconfig codeindex 命令控制索引。您可以指定要索引/indexHistoryPeriod:#months 多久之前,完全删除索引/destroyCodeIndex 或排除特定有问题的文件/ignoreList:add $/path

Code Lens 在产品内部也被称为 Code Sense 和 Code Index。

More can be found here.

如果删除索引超时,you read this post on StackOverflow with additional guidance。请注意,不支持在 TFS 集合 DB 上手动运行 SQL。

测试附件

哦,是的,尤其是当您使用测试附件时,这些附件可能会变得疯狂,这取决于您的 TFS 版本,要么使用内置的测试附件清理功能,要么使用 TFS 电动工具中的测试附件清理器。

XAML 构建

构建定义本身不会占用大量数据库空间,但构建结果可能会。但这些内容已在上一节中介绍过。

过去,我不得不修补 tfbuid.exe 来处理(非常)大量的构建记录,因为它倾向于在继续删除操作之前尝试在本地获取所有构建数据。您可能需要依靠 TFS 客户端对象模型来获得类似的结果。

Git 存储库

您的 git 存储库中的数据可能由于强制推送或删除的分支而不再可访问。也有可能 Git 中的某些数据可以更有效地打包。要清理存储库,您必须在本地克隆它们,清理它们,从 TFS 中删除远程存储库并将清理后的副本推送到新存储库(您可以使用与旧存储库相同的名称)。这样做会破坏现有构建定义的引用,您将不得不修复它们。当您使用它时,您还可以运行 BFG repo Cleaner 并转换存储库以启用 Git-LFS 支持,从而更优雅地处理存储库中的大型二进制文件。

git clone --mirror https://tfs/project/repo
# optionally run BFG repo cleaner at this point
git reflog expire --expire=now --all 
git gc --prune=now --aggressive
git repack -adf
# Delete and recreate the remote repository with the same name
git push origin --all
git push origin --tags

工作项目(附件)

工作项可以收集大量数据,尤其是当人们开始将大型附件附加到它们时。您可以使用witadmin destroywi 删除附件过大的工作项。要保留工作项,但删除其附件,您可以从当前工作项中删除附件,然后克隆它。克隆后,销毁旧工作项以清理附件。

您不再需要的旧工作项目(例如 6 年前的 sprint 项目)也可以删除。 My colleague René has a nice tool that allows you to bulk-destroy by first creating the appropriate work item query.

确保运行清理作业

TFS 通常不会立即从数据库中删除数据,在许多情况下,它只是将内容标记为已删除以供以后处理。要强制立即进行清理,请在您的项目集合数据库上运行以下存储过程:

EXEC prc_CleanupDeletedFileContent 1
# You may have to run the following command multiple times, the last
# parameter is the batch size, if there are more items to prune than the 
# passed in number, you will have to run it multiple times
EXEC prc_DeleteUnusedFiles 1, 0, 100000

最后的 100000 是要处理的标记项目的数量。如果您删除了很多内容,您可能需要运行最后一个过程几次,然后才会删除所有内容。

其他有用的查询

要确定每个部分中存储了多少数据,您可以运行一些有用的查询。实际查询取决于您的 TFS 版本,但由于您正在准备迁移,我怀疑您目前使用的是 TFS 2017 或 2018。

查找最大的表:

SELECT TOP 10 
    o.name, 
    SUM(reserved_page_count) * 8.0 / 1024 SizeInMB,
    SUM(
        CASE 
              WHEN p.index_id <= 1 THEN p.row_count
              ELSE 0
        END) Row_Count
FROM sys.dm_db_partition_stats p
JOIN sys.objects o
    ON p.object_id = o.object_id
GROUP BY o.name
ORDER BY SUM(reserved_page_count) DESC

找到最大的内容贡献者:

SELECT Owner = 
    CASE
        WHEN OwnerId = 0 THEN 'Generic' 
        WHEN OwnerId = 1 THEN 'VersionControl'
        WHEN OwnerId = 2 THEN 'WorkItemTracking'
        WHEN OwnerId = 3 THEN 'TeamBuild'
        WHEN OwnerId = 4 THEN 'TeamTest'
        WHEN OwnerId = 5 THEN 'Servicing'
        WHEN OwnerId = 6 THEN 'UnitTest'
        WHEN OwnerId = 7 THEN 'WebAccess'
        WHEN OwnerId = 8 THEN 'ProcessTemplate'
        WHEN OwnerId = 9 THEN 'StrongBox'
        WHEN OwnerId = 10 THEN 'FileContainer'
        WHEN OwnerId = 11 THEN 'CodeSense'
        WHEN OwnerId = 12 THEN 'Profile'
        WHEN OwnerId = 13 THEN 'Aad'
        WHEN OwnerId = 14 THEN 'Gallery'
        WHEN OwnerId = 15 THEN 'BlobStore'
        WHEN OwnerId = 255 THEN 'PendingDeletion'
    END,
    SUM(CompressedLength) / 1024.0 / 1024.0 AS BlobSizeInMB
FROM tbl_FileReference AS r
JOIN tbl_FileMetadata AS m
    ON r.ResourceId = m.ResourceId
    AND r.PartitionId = m.PartitionId
WHERE r.PartitionId = 1
GROUP BY OwnerId
ORDER BY 2 DESC

如果文件容器是问题:

SELECT 
    CASE 
        WHEN Container = 'vstfs:///Buil' THEN 'Build'
        WHEN Container = 'vstfs:///Git/' THEN 'Git'
        WHEN Container = 'vstfs:///Dist' THEN 'DistributedTask'
        ELSE Container 
    END AS FileContainerOwner,
    SUM(fm.CompressedLength) / 1024.0 / 1024.0 AS TotalSizeInMB
FROM 
    (SELECT DISTINCT LEFT(c.ArtifactUri, 13) AS Container,
    fr.ResourceId,
    ci.PartitionId
FROM tbl_Container c
INNER JOIN tbl_ContainerItem ci
    ON c.ContainerId = ci.ContainerId
    AND c.PartitionId = ci.PartitionId
INNER JOIN tbl_FileReference fr
    ON ci.fileId = fr.fileId
    AND ci.DataspaceId = fr.DataspaceId
    AND ci.PartitionId = fr.PartitionId) c
INNER JOIN tbl_FileMetadata fm
    ON fm.ResourceId = c.ResourceId
    AND fm.PartitionId = c.PartitionId
GROUP BY c.Container
ORDER BY TotalSizeInMB DESC

【讨论】:

  • 感谢 Jesse 在您的网站和帖子中所做的所有努力,我知道我过去也发现了它。我现在遇到的是我的管道://b FileContainer 的大小增加到 110GB。您对如何将其缩小到一个项目甚至最大的构建定义有什么建议吗?顺便说一句,运行“TFS”2019。
  • 我已经很长时间不得不深入研究架构的那一部分了。必须有一个可以追溯到项目的标识符,或者,我猜是构建定义 ID。
  • @Nico 有一个客户要求深入挖掘......查询仍然很粗糙,但它聚合到团队项目和回购/发布定义/构建定义。尚未涵盖所有数据类型,可能需要进一步调整...gist.github.com/jessehouwing/97de4849a8a81cf3ebc39a9eab4e8f0d
  • 谢谢杰西!如果您有兴趣,我运行了您的脚本。它运行了 11 分钟,返回了 608 行。最大的行有项目集和 FriendlyName NULL,这一行是 47GB,显示有 487344 行。第二行是在 4834 行中声明 16GB 的构建定义。 NULL 是预期的还是您可能正在处理的事情?如果你想要我的数据,请告诉我是否可以提供帮助。
  • @nico 我已经实现了几个查找。如果没有更多数据(以及对数据库的访问),很难说它为什么返回 null。
【解决方案2】:

我的 TFS 2015 服务器托管了多个 GIT 存储库,其中一些具有非常大的文件(使用 LFS)。使用 TFS Web 界面,我删除了一些在 tbl_content 中占用大量存储空间的测试存储库,我注意到文件没有从数据库中删除。

我几乎尝试了所有方法。 tf delete 没用,因为 repo 已经被删除。 存储过程 prc_* 没有多大帮助。刚刚从 50 GB 减小到 41 GB

正确清理 tbl_content 数据库的唯一方法是执行 SQL 查询:

DELETE FROM tbl_content WHERE ResourceId IN (SELECT A.[ResourceId]  
  FROM [dbo].[tbl_Content] As A
  WHERE A.ResourceId NOT IN (SELECT X.ResourceId FROM tbl_filemetadata as X)
  AND A.ResourceId NOT IN (SELECT Y.ResourceId from tbl_filereference as Y))

这个过程花了半个多小时。之后,我执行了数据库收缩。现在表大小为 17 GB。

现在我会将所有 GIT 存储库从 TFS 移动到自托管的 Gitea 服务器。与贪婪且不可维护的 TFS 相比,服务器非常轻量级和高效......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多