got*_*tqn 6 compression sql-server-2012 sql-clr
我创建了一个简单的 CLR 函数来压缩/解压缩NVARCHAR
列:
[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
public static SqlBinary Compress( string str ){
if( str == null ){return new SqlBinary();}
if( String.IsNullOrEmpty( str ) ){str = " ";}
byte[] bytes = Encoding.Unicode.GetBytes( str );
using( MemoryStream msi = new MemoryStream( bytes ) ){
using( MemoryStream mso = new MemoryStream() ){
using( GZipStream gs = new GZipStream( mso, CompressionMode.Compress ) ){
msi.CopyTo( gs );
}
return new SqlBinary( mso.ToArray() );
}
}
}
Run Code Online (Sandbox Code Playgroud)
我得到的压缩率大约是 4,或者如果我有 1024 KB 的未压缩数据,我将得到 256 KB 的压缩数据。我知道比率取决于数据本身及其大小,但我想获得更好的比率。
由于我使用SQL Server 2012和.NET 4.0,是有变化的是,按压不给,因为像问题的预期比这个?
是否有我可以在 SQL CLR 函数中使用的替代类?有这样的替代方案,但目前不支持。
这里有一些关于这个的想法:
您知道您应该对测试过的字符串进行更好的压缩吗?您是否通过 .NET 之外的 gzip 测试过这些相同的字符串?比如在Linux/CygWin上——UNIX实用程序/PHP/等的DOS端口?
如果您已经更新您的系统与.NET 4.5,那么你正在使用更新的GZipStream。这是因为它在System.dll 中,这是一个受支持的库。您可以使用允许CompressionLevel的新构造函数对此进行测试。只需更改CompressionMode.Compress
为CompressionLevel.Optimal
. SQL Server 绑定到特定版本的CLR,而不绑定到特定版本的.NET Framework。这意味着,任何受支持库中的任何新功能都可以使用,只要您将代码部署到的任何服务器都已更新其 .NET。
这并不意味着您将获得更好的压缩。我测试了这段代码,它为 PHP 和 Fiddler 生成的“Hello World”提供了相同的 31 个字节,如您链接到的问题之一所述:https : //stackoverflow.com/questions/11435200/why-does -my-c-sharp-gzip-produce-a-larger-file-than-fiddler-or-php。
我刚刚用一串 3405 个随机字符(即“fsdkjf skdj f...”)再次测试。NVARCHAR(4000)
在进行了我在此处建议的更改后,我将变量声明为 as并在您的代码中运行它。压缩二进制文件的长度为 211 字节。然后我将相同的字符串复制并粘贴到 Notepad++ 中,确保将编码设置为“UCS-2 Little Endian”并保存。我在 Windows 资源管理器中检查了该文件,它是 6812 字节(数据中的 6810,也由变量的 DATALENGTH 报告,加上字节顺序标记的 2)。我以二进制模式将它传输到 Linux 服务器。Linux 服务器上的文件大小仍为 6812。然后我运行gzip -9
它(即最大压缩;默认为-6
)。压缩尺寸?231 字节。所以 .NET GZipStream 实际上稍微好一些。
CompressionMode.Compress
并且CompressionLevel.Optimal
在功能上是等效的。在指定另一个时,每个都是假定的默认值。
不要string
用于输入参数;使用SqlString
.
摆脱byte[] bytes
线
new MemoryStream( bytes )
将第一个using
块更改为:
new MemoryStream(str.GetUnicodeBytes())
你可以摆脱这if( str == null ){return new SqlBinary();}
条线。无需在 .NET 代码中处理此问题,只需添加WITH RETURNS NULL ON NULL INPUT
到CREATE FUNCTION 即可。这样,如果输入为 NULL ,SQL Server 甚至不会调用您的代码 :)。请记住,当您有多个输入参数时,如果其中任何一个为 NULL ,此选项将返回NULL。如果自然地至少其中一个应该能够传入 NULL,那么您必须在代码中处理这种情况。
替换这一行if( String.IsNullOrEmpty( str ) ){str = " ";}
——它实际上返回一个不是空字符串的压缩空间——用:
if (str.Value.Length == 0)
{
return SqlBinary.Null;
}
Run Code Online (Sandbox Code Playgroud)我还没有尝试过“zlib”,但不幸的是,“SharpZipLib”和“DotNotZip”都有问题,并且已经好几年没有更新了,也没有迹象表明它们会更新。但是,“DotNetZip”中的错误似乎主要与 zip 文件存档有关,而不是 GZip 功能(它在SQL# 中运行良好:-))。