SQL Server 2012 文件表在创建文件时性能降低(集成 Lucene.NET)
本文关键字:文件 集成 Lucene NET 2012 Server SQL 创建 性能 | 更新日期: 2023-09-27 18:33:13
我一直在使用SQL Server FileTable构建一种将 Lucene.NET 与SQL Server集成的方法。用法非常方便,代码很简单 - 我不必对自定义 Lucene.NET 做任何特别的事情。我寻求的优势主要是操作和企业 - 我的公司运行SQL Server 24/7,将搜索索引保持在同一控制空间中对我们来说有很多优势(...而且我确实意识到我不会获得精确的事务一致性,这没关系(。
问题:无论我做什么,在使用 WinAPI(通过 System.IO.FileStream(写入 SQL FileTable UNC 共享中的文件时,似乎都有大约 200 毫秒(+- 20-30 毫秒(的开销。这对于 Lucene.NET 很重要,因为直接对我的本地文件系统执行索引写入操作需要 ~50 毫秒,而对 FileTable 执行相同的操作需要 ~2-3 秒!
为了检查这一点,我创建了另一个实验,该实验以 10KB、1MB 和 10MB 写入 3 个新(创建(文件。我把这 3 个文件写到:
- 本地目录 (
c:'Search''
( - 通过 UNC 路径的非文件表共享 (
'''127.0.0.1''Search''
( - 文件表 UNC 路径 (
'''127.0.0.1'[instance-share]''search_index''
(
使用 System.Diagnostics.Stopwatch
,写入本地目录的速度与预期一样快,写入非 FileTable 共享的速度较慢但相当,而 FileTable 慢了一个数量级。有趣的是,在案例 2 和 3 中执行的 2 个较大的文件大小类似,这让我相信文件创建的开销与时间相当。
问题:有没有人更深入地了解为什么使用FileTable创建文件如此"缓慢"?
这是一个并发活动很少的开发 VM(4GB RAM、2 个 vCPU,可能有一些 IO 争用,但这些测试旨在进行相对比较(。插入到 SQL Server 中,因为此框上的一行微不足道,几乎不会达到 1 毫秒。
我手边没有代码,但很快就会发布编辑(有确切的时间( - 它非常简单,只是将静态初始化字节数组的 4K 块循环写入所需的大小。
我确实实施了以下建议,并且还调整了 SMB 堆栈,性能没有差异:http://blogs.msdn.com/b/blogdoezequiel/archive/2011/02/11/best-practices-on-filestream-implementations.aspx#.UkbEYtKshcZ
编辑:来自输出测试控制台的计时:
Writing files for directory: c:'Search
Writing file size : 10240
Writing file size : 1048576
Writing file size : 10485760
Writing files for directory: ''127.0.0.1'Search
Writing file size : 10240
Writing file size : 1048576
Writing file size : 10485760
Writing files for directory: ''127.0.0.1'Sql2012'FIndex'search_index
Writing file size : 10240
Writing file size : 1048576
Writing file size : 10485760
Write Timings
---------------------------------------------------------------
Paths (rows): Local, Shared, SQL File Table
Sizes (columns): 10KB, 1MB, 10MB
---------------------------------------------------------------
Local: 3 2 17
Share: 28 31 64
FTable: 205 249 317
源代码(非常简单,为完整起见而发布(:省略了 ASCII 艺术的控制台主:
private static readonly string[] paths = new string[]
{
@"c:'Search",
@"''127.0.0.1'Search",
@"''127.0.0.1'Sql2012'FIndex'search_index"
};
private static readonly int[] sizes = new int[]
{
1024 * 10,
1024 * 1024,
1024 * 1024 * 10
};
static void Main(string[] args)
{
// Directory: Size 1, 2, 3
var timings = new long[3, 3];
var stopwatch = new Stopwatch();
for(var x = 0; x < 3; x++)
{
Console.WriteLine("Writing files for directory: {0}", paths[x]);
for(var y = 0; y < 3; y++)
{
Console.WriteLine("'tWriting file size : {0}", sizes[y]);
string fileName = Path.Combine(paths[x], Guid.NewGuid().ToString() + ".bin");
stopwatch.Start();
FileIOTestHelper.WriteFile(fileName, sizes[y]);
stopwatch.Stop();
timings[x, y] = stopwatch.ElapsedMilliseconds;
stopwatch.Reset();
}
}
// ascii art display code
}
实现类:
public static class FileIOTestHelper
{
private static readonly byte[] testBuffer = CreateBuffer();
private static byte[] CreateBuffer()
{
var buffer = new byte[4096];
for (var i = 0; i < 4096; i++)
{
buffer[i] = (byte)(i % 256);
}
ForceIOJit(buffer);
return buffer;
}
private static void ForceIOJit(byte[] initBuffer)
{
// Shouldn't matter, but eliminating any possible warm up cost.
using (var fs = new FileStream(Path.GetTempFileName(), FileMode.Open))
{
fs.Write(initBuffer, 0, 4096);
fs.Flush();
}
}
public static void WriteFile(string name, int sizeInBytes)
{
var count = sizeInBytes / 4096;
var remainder = sizeInBytes % 4096;
using (var fs = new FileStream(name, FileMode.Create))
{
for (int i = 0; i < count; i++)
{
fs.Write(testBuffer, 0, 4096);
}
if (remainder > 0)
{
fs.Write(testBuffer, 0, remainder);
}
fs.Flush();
}
}
}
经过更多的测试,我遇到的延迟是一致的,并且对缓冲区大小不敏感。我接受这是FileTable的限制,对于非常健谈的IO来说,它不太理想。