65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 CLR 辅助在 T-SQL 中复制文件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.17/5 (4投票s)

2013年1月21日

CPOL

3分钟阅读

viewsIcon

15387

downloadIcon

8

使用 FileRelay CLR 可以更简单地管理 SQL 备份。

引言

在我的一生中,我曾多次为如何从本地机器将 SQL 备份从 Server-A 复制到 Server-B 的问题而苦恼。  

由于我与 SQL 服务器位于不同的地点(城市、国家、大陆),这使得情况更加复杂。理想情况下,我可以远程连接到其中一个服务器,然后直接在它们之间复制文件(这是一种不方便的解决方案,但无疑是最有效的)。有时我无法远程连接,但我可以访问共享文件夹,通过这种方式复制文件会导致高网络负载,并且复制方法很慢。当服务器内存设置的最小值和最大值不同,并且服务器上没有可分配的空闲内存时,文件复制还可能导致内存压力问题。  

由于管理工具 (Management Studio) 始终在我面前,对我来说,最方便的解决方案是能够从这里发出文件复制命令,还可以指定单次传输的字节数,以防止内存压力问题。   

上述问题的解决方案是 FileRelay CLR。   您将能够通过 T-SQL 命令在 SQL 服务器之间复制文件。  

 

背景

公共语言运行时 (CLR) 是 Microsoft .NET Framework 的核心,它为所有 .NET Framework 代码提供执行环境。在 CLR 中运行的代码称为托管代码。CLR 提供了程序执行所需的各种函数和服务,包括即时 (JIT) 编译、内存分配和管理、类型安全强制执行、异常处理、线程管理和安全性。

通过 Microsoft SQL Server 中托管的 CLR(称为 CLR 集成),您可以使用托管代码编写存储过程、触发器、用户定义函数、用户定义类型和用户定义聚合。由于托管代码在执行前会被编译为本机代码,因此在某些场景下可以获得显著的性能提升。   

有三个权限集:SAFEEXTERNAL_ACCESSUNSAFE。  

SQL Server 在托管 CLR 时提供了一个主机级别的安全策略。此策略是始终生效的两个策略级别之下的一个附加策略级别。此策略针对 SQL Server 创建的每个应用程序域进行设置。此策略不适用于 SQL Server 创建 CLR 实例时生效的默认应用程序域。  

  • SAFE:只允许内部计算和本地数据访问。SAFE 是最严格的权限集。具有 SAFE 权限的程序集执行的代码无法访问外部系统资源,例如文件、网络、环境变量或注册表。

  • EXTERNAL_ACCESS:与 SAFE 权限集类似,但增加了访问外部系统资源(如文件、网络、环境变量和注册表)的能力。  

  • UNSAFE:UNSAFE 允许程序集不受限制地访问 SQL Server 内部和外部的资源。从 UNSAFE 程序集内部执行的代码可以调用非托管代码。   

部署 CLR    

您可以通过运行 fast_install_clr.sql.txt 脚本或遵循以下步骤来部署 CLR。  
首先启用 CLR,然后创建程序集即可:    

use [master]
GO
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE; 
GO  
 
CREATE ASSEMBLY [kladna.sql.filerelay]  
FROM 'D:\CLR\kladna.sql.filerelay.dll'
WITH PERMISSION_SET = UNSAFE
GO   

其次创建 CLR 函数

-- Copy File -------------------------
CREATE FUNCTION dbo.clr_filerelay_copy(@instance_name nvarchar(128), @source_file_stream nvarchar(4000), 
   @target_file_stream nvarchar(4000), @target_server_conn_string nvarchar(4000), @stream_copy_batch_mb int)
RETURNS bit
AS
EXTERNAL NAME [kladna.sql.filerelay].[FileRelay].[Copy]
GO
 
-- Write Bytes ------------------------------
CREATE FUNCTION dbo.clr_filerelay_write_bytes(@target_file_stream nvarchar(4000), 
  @position bigint, @bytes varbinary(max), @retry int)
RETURNS bit
AS
EXTERNAL NAME [kladna.sql.filerelay].[FileRelay].[WriteBytes]
GO
 
-- Get Size of a File -------------------------
CREATE FUNCTION dbo.clr_filerelay_get_file_size(@filename nvarchar(4000))
RETURNS bigint
AS
EXTERNAL NAME [kladna.sql.filerelay].[FileRelay].[GetFileSize]
GO
 
-- Get Stat of a copy-instance --------------------
CREATE FUNCTION dbo.clr_filerelay_get_instance_stat(@instance_name nvarchar(128))
RETURNS table (current_step nvarchar(1000), source_file_stream nvarchar(4000), 
  target_file_stream nvarchar(4000), stream_copy_batch_bytes int, 
  source_size bigint, target_start_size bigint, target_size bigint, 
  ellapsed_sec_total int,  ellapsed_sec_reader_total int, ellapsed_sec_reader_last int, 
  ellapsed_sec_writer_total int, ellapsed_sec_writer_last int, estimated_sec_remaining int, 
  percent_completed int, avg_kb_reads_per_sec int, avg_kb_writes_per_sec int, total_bytes_copied bigint)
AS
EXTERNAL NAME [kladna.sql.filerelay].[FileRelay].[GetInstanceStats]
GO
 
-- Get list of Errors -----------------------
CREATE FUNCTION dbo.clr_filerelay_list_errors()
RETURNS table (instance nvarchar(1000), error_msg nvarchar(max))
AS
EXTERNAL NAME [kladna.sql.filerelay].[FileRelay].[ListErrors]
GO
 
-- Clear Errors ------------------------------
CREATE FUNCTION dbo.clr_filerelay_clear_errors()
RETURNS bit
AS
EXTERNAL NAME [kladna.sql.filerelay].[FileRelay].[ClearErrors]
GO 

CLR 函数   

  • clr_filerelay_copy  
    此方法执行 Server A 和 Server B 之间的复制本身  
    • @instance_name - 复制过程的唯一名称
    • @source_file_stream - Server A 上的要复制的文件
    • @target_file_stream - Server B 上的复制文件
    • @target_server_conn_string - Server B 的 SQL 连接字符串(.NET 格式) @stream_copy_batch_mb - 单个周期传输的字节数(以兆字节为单位)

    复制完成时返回 1,复制过程中发生错误时返回 0   

  • clr_filerelay_list_errors    
    复制失败时,您可以检查错误原因  
  • clr_filerelay_clear_errors
    您可以清除错误以释放一些内存    
  •  clr_filerelay_get_instance_stat
    在复制过程中,您可以检查与复制过程相关的一些信息:  
    • 剩余估算秒数
    • 完成百分比
    • 平均每秒读取千字节数
    • 平均每秒写入千字节数
    • 复制的总字节数    

使用代码

只有当上述 CLR 已部署到两个 SQL 服务器上时,才允许在 SQL 服务器之间进行复制。让我们看看如何复制文件:  

select dbo.clr_filerelay_copy('my_first_test'
			     ,'c:\my_backup_20130121.bak'
			     ,'c:\my_backup_20130121.bak' 
			     ,'Data Source=SQL2\Instance2;Initial Catalog=master;User Id=me;Password=passw;'
			     ,10) 

在不同的查询窗口中,您可以检查统计信息

 select estimated_sec_remaining
	  ,percent_completed
	  ,avg_kb_reads_per_sec
	  ,avg_kb_writes_per_sec
	  ,total_bytes_copied
 from dbo.clr_filerelay_get_instance_stat('my_first_test')   

检查并删除错误:  

select * from dbo.clr_filerelay_list_errors()	
select dbo.clr_filerelay_clear_errors()  

值得关注的方面   

有趣的是,SQL 引擎可以通过文件复制进行操作。我能够以 80MB/秒的速度将文件从 A 移动到 B。

© . All rights reserved.