3

私は、SQL Server FileTable を使用して Lucene.NET を SQL Server と統合するアプローチのプロトタイプを作成しています。使用法は非常に便利で、コードは単純です。Lucene.NET のカスタマイズで特別なことをする必要はありません。私が求める利点は、主に操作性とエンタープライズ性です。私の会社は SQL Server を 24 時間年中無休で運用しており、検索インデックスを同じ制御スペースに保持することは、私たちにとって多くの利点があります (...そして、正確なトランザクションが得られないことはわかっています)。一貫性、それで問題ありません)。

問題: 私が何をしても、(System.IO.FileStream 経由で) WinAPI を使用して SQL FileTable UNC 共有内のファイルに書き込むときに、約 200 ミリ秒 (+- 20 ~ 30 ミリ秒) のオーバーヘッドがあるようです。これは Lucene.NET では重要です。なぜなら、ローカル ファイル システムへの直接のインデックス書き込み操作には約 50 ミリ秒かかるのに対し、FileTable への同じ操作には約 2 ~ 3 秒かかるからです。

これを確認するために、10KB、1MB、10MB の 3 つの新しい (作成) ファイルを書き込む別の実験を作成しました。これらの 3 つのファイルを次の場所に書き込みました。

  1. ローカル ディレクトリ ( c:\Search\\)
  2. UNC パス経由の非 FileTable 共有 ( \\\127.0.0.1\\Search\\)
  3. FileTable UNC パス ( \\\127.0.0.1\[instance-share]\\search_index\\)

を使用System.Diagnostics.Stopwatchすると、ローカル ディレクトリへの書き込みは予想どおり最速でした。FileTable 以外の共有への書き込みは低速でしたが同等であり、FileTable は桁違いに低速でした。興味深いのは、ケース 2 と 3 で 2 つの大きなファイル サイズが同様に実行されたことです。これにより、ファイル作成のオーバーヘッドがタイミングのレベルにあると考えられます。

質問: FileTable を使用したファイル作成が非常に「遅い」理由について、より深い洞察を持っている人はいますか?

これは、同時アクティビティがほとんどない開発用 VM です (4 GB の RAM、2 つの vCPU、おそらく IO の競合がありますが、これらのテストは相対的な比較を目的としています)。このボックスの簡単な行の SQL Server への挿入は、かろうじて 1 ミリ秒に達します。

コードは手元にありませんが、すぐに編集して投稿します(正確なタイミングで)-非常に単純で、静的に初期化されたバイト配列の4Kチャンクをループで目的のサイズに書き込むだけです。

次の推奨事項を実装し、SMB スタックも調整しましたが、パフォーマンスに違いはありませんでした 。 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();
        }
    }
}
4

1 に答える 1