1

私は 97 のメンバー、つまり物理シャードを持つ SQL フェデレーションを持っています。各メンバーには、1 ~ 16 個の仮想シャード、つまりアトミック ユニットがあります。このデータ層は、検索ルックアップ Web サービス (Azure Web ロール Web サーバー上) を強化します。このサービスでは、ユーザーの応答に十分な回答を得る前に、すべてのアトミック ユニットが応答する必要があります。

検索パラメーターが与えられると、Web サーバーは照会する必要があるアトミック ユニット ID を特定できますが、関連するフェデレーション メンバーは特定できません (この変換には USE フェデレーションを使用しています)。目標は、Web サーバーがすべての原子単位 (どこにあるかに関係なく) を可能な限り迅速に照会するようにすることです。

現在、これに対する最善の解決策は次のように機能します。

  1. 必要な原子単位のリストを生成します。
  2. アトミック ユニットごとに USE フェデレーションと SQL ステートメントを生成します。現在、私が見つけた最高のパフォーマンスは、USE フェデレーション ステートメントで FILTERING = OFF を指定し、SQL ステートメントでアトミック ユニットの述語を手動で指定することです (これらの述語を追加するために FILTERING = ON に依存するのではなく)。
  3. アトミック ユニットごとに、フェデレーション ルートへの SqlConnection を開き、USE フェデレーション ステートメントを実行してから、SQL クエリを両方とも非同期で実行します。TPL Dataflow ライブラリと async/await を使用して、すべてのアトミック ユニット クエリが終了するのを待ちます。その後、結果にビジネス ロジックを適用し (Web 要求によってはオプション)、応答を返します。

これらのクエリの各アトミック ユニットは 100 ~ 600 レコードを返しますが、2000 を超えることはありません。設計目標は、最大 200 アトミック ユニットを一度にクエリすることです => したがって、400,000 レコードが Web サーバーが適用する必要がある最大量です。ただし、そのロジックは「結果の個別の数値 ID ごとに 1 つのオブジェクトを取得する」以上のものではありませんが、そのために IEqualityComparer を実装しました。

このアプローチは、それほどうまくスケーリングされていないようです。30 ~ 40 のアトミック ユニットをクエリする場合でも、個々のアトミック ユニットの応答にかかる時間がそれぞれ 1 秒未満であることをテストして確認できますが、応答時間は著しく増加します。

私の問題の可能性が高い場所は次のとおりだと思います。

  1. アトミック ユニット クエリごとに個別の SqlConnection を使用する => 接続プールを効果的に活用していますか?
  2. ビジネス ロジックとオブジェクトのシリアライゼーション => アトミック ユニット間で異なる操作にアプローチする必要がありますか? 他のフィールドでも合計演算を実行したい場合はどうすればよいでしょうか (デフォルトの使用例ではなく、一般的な使用例です)。

誰かがこれを処理するお気に入りの方法を持っている場合は、それについて聞いてみたい. ありがとう。

現在の解決策:

        #region Identify atomic units of search query from search parameters (static methods, no i/o, very fast)
        List<string> AtomicUnits = AtomicUnitsOfSearch(data);
        #endregion                       

        #region Atomic unit-targeted subqueries setup
        var atomicUnitQueries = AtomicUnits.Select(au => 
            {                    
                return GetItemsFromAtomicUnit(
                    CreateConstraintSQLQuery(data), 
                    au,
                    verbosity);
            });            
        #endregion

        #region Execute async query across relevant shards; Distinct result item summary query business logic
        if (Verbosity.basic.Equals(verbosity)) // return one item per conceptid
        {
            return (await TaskEx.WhenAll(atomicUnitQueries)).SelectMany(a => a)                    
                .Distinct(new SimpleItemComparer()).ToList(); // Distinct() the fan-out results based on ID
        }
        else // assume _count verbosity => pick one item per Id, sum Categories and Item counts across atomic units (do not double-count for synonyms)
        { 
            // create the ending schema before executing the results lookup
            List<Item> atomicResults = (await TaskEx.WhenAll(atomicUnitQueries)).SelectMany(a => a).ToList();
            List<Item> distinctResults = new List<Item>();
            foreach (IGrouping<int, Item> g in atomicResults.GroupBy(a => a.Id)) // gets the lists of equivalent items across all atomic units queried
            {
                Item f = g.First();
                distinctResults.Add(new Item(f.Id, f.Name, g.Sum(a => a.CategoryCount), g.Sum(a => a.ItemCount)));
            }
            return distinctResults;                
        }                        
        #endregion

4

0 に答える 0