1

データアクセス層としてNhibernateを使用しています。検索のためにLuceneを介して1つずつインデックスを作成する必要がある170万レコードのテーブルがあります。インデックスを作成するために作成したコンソールアプリを実行すると、最初は速くなりますが、アイテムが進むにつれて、徐々に遅くなります。

最初の反復は、それらすべてにインデックスを付けることでした。2番目の反復は、カテゴリ別にインデックスを作成することでした。現在、カテゴリ別にサブセットを選択し、それらを100の「ページ」に分割しています。パフォーマンスはまだ低下しています。

SQLプロファイラーをオンにすると、アイテムを反復処理するときに、画像に対して遅延読み込みが設定されていなくても、画像に対して各アイテムのSQLサーバーが1つずつ呼び出されます。

これはコマースサイトであり、カタログアイテム(製品)のインデックスを作成しています。各カタログアイテムには、0から多数の画像があります(個別のテーブルに保存されます)。

これが私たちのマッピングです:

public class ItemMap : ClassMap<Item>
    {
        public ItemMap()
        {
            Table("Products");

            Id(x => x.Id, "ProductId").GeneratedBy.GuidComb();

            Map(x => x.Model);
            Map(x => x.Description);

            Map(x => x.Created);
            Map(x => x.Modified);
            Map(x => x.IsActive);
            Map(x => x.PurchaseUrl).CustomType<UriType>();

            Component(x => x.Identifier, m =>
                {
                    m.Map(x => x.Upc);
                    m.Map(x => x.Asin);
                    m.Map(x => x.Isbn);
                    m.Map(x => x.Tid);
                });

            Component(x => x.Price, m =>
                {
                    m.Map(x => x.Currency);
                    m.Map(x => x.Amount, "Price");
                    m.Map(x => x.Shipping);
                });

            References(x => x.Brand, "BrandId");
            References(x => x.Category, "CategoryId");
            References(x => x.Supplier, "SupplierId");
            References(x => x.Provider, "ProviderId");

            HasMany(x => x.Images)
                .Table("ProductImages")
                .KeyColumn("ProductId")
                .Not.LazyLoad();




            // TODO: Add variants





        }

    }

そして、これがインデックス作成アプリのルートロジックです。

public void IndexProducts()
        {
            Console.WriteLine("--- Begin Indexing Products ---");
            Console.WriteLine();
            var categories = categoryRepository.GetAll().ToList();
            Console.WriteLine(String.Format("--- {0} Categories found ---", categories.Count));
            categories.Add(null);

            foreach (var category in categories)
            {
                string categoryName = "\"None\"";

                if (category != null)
                    categoryName = category.Name;

                Console.WriteLine(String.Format("--- Begin Indexing Category ({0}) ---", categoryName));
                var categoryItems = from p in catalogRepository.GetList(new ActiveProductsByCategoryQuery(category))
                                    select p;

                int count = categoryItems.Count();
                int pageSize = 100;
                int currentPage = 0;
                int offest = currentPage * pageSize;
                int current = 1;

                Console.WriteLine(String.Format("Indexing {0} Products...", count));

                while (offest < count)
                {
                    var products = (from p in categoryItems
                                    select p).Skip(offest).Take(pageSize);

                    foreach (var item in products)
                    {
                        indexer.UpdateContent(item);
                        UpdateCounter(current, count);
                        current++;
                    }

                    currentPage++;
                    offest = currentPage * pageSize;
                }
                Console.WriteLine();

                Console.WriteLine(String.Format("--- End Indexing Category ({0}) ---", categoryName));
                Console.WriteLine();
            }

            Console.WriteLine("--- End Indexing Products ---");
            Console.WriteLine();
        }

参考までに、問題のカテゴリのカウントは26552です。実行される最初のクエリは次のとおりです。

exec sp_executesql N'SELECT TOP 100 ProductId100_1_, Upc100_1_, Asin100_1_, Isbn100_1_, Tid100_1_, Currency100_1_, Price100_1_, Shipping100_1_, Model100_1_, Descrip10_100_1_, Created100_1_, Modified100_1_, IsActive100_1_, Purchas14_100_1_, BrandId100_1_, CategoryId100_1_, SupplierId100_1_, ProviderId100_1_, CategoryId103_0_, Name103_0_, ShortName103_0_, Created103_0_, Modified103_0_, ShortId103_0_, DisplayO7_103_0_, IsActive103_0_, ParentCa9_103_0_ FROM (SELECT this_.ProductId as ProductId100_1_, this_.Upc as Upc100_1_, this_.Asin as Asin100_1_, this_.Isbn as Isbn100_1_, this_.Tid as Tid100_1_, this_.Currency as Currency100_1_, this_.Price as Price100_1_, this_.Shipping as Shipping100_1_, this_.Model as Model100_1_, this_.Description as Descrip10_100_1_, this_.Created as Created100_1_, this_.Modified as Modified100_1_, this_.IsActive as IsActive100_1_, this_.PurchaseUrl as Purchas14_100_1_, this_.BrandId as BrandId100_1_, this_.CategoryId as CategoryId100_1_, this_.SupplierId as SupplierId100_1_, this_.ProviderId as ProviderId100_1_, category1_.CategoryId as CategoryId103_0_, category1_.Name as Name103_0_, category1_.ShortName as ShortName103_0_, category1_.Created as Created103_0_, category1_.Modified as Modified103_0_, category1_.ShortId as ShortId103_0_, category1_.DisplayOrder as DisplayO7_103_0_, category1_.IsActive as IsActive103_0_, category1_.ParentCategoryId as ParentCa9_103_0_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM Products this_ left outer join Categories category1_ on this_.CategoryId=category1_.CategoryId WHERE (this_.IsActive = @p0 and (1=0 or (this_.CategoryId is not null and category1_.CategoryId = @p1)))) as query WHERE query.__hibernate_sort_row > 500 ORDER BY query.__hibernate_sort_row',N'@p0 bit,@p1 uniqueidentifier',@p0=1,@p1='A988FD8C-DD93-4119-8F84-0AF3656DAEDD'

次に、製品ごとに実行されます

exec sp_executesql N'SELECT images0_.ProductId as ProductId1_, images0_.ImageId as ImageId1_, images0_.ImageId as ImageId98_0_, images0_.Description as Descript2_98_0_, images0_.Url as Url98_0_, images0_.Created as Created98_0_, images0_.Modified as Modified98_0_, images0_.ProductId as ProductId98_0_ FROM ProductImages images0_ WHERE images0_.ProductId=@p0',N'@p0 uniqueidentifier',@p0='487EA053-4DD5-4EBA-AA36-95B30C42F0CD'

どちらでも構いません。問題は、最初の2000かそこらが本当に速いことですが、カテゴリを実行する時間が長くなるほど、同じ数の製品にインデックスを付けていても、取得が遅くなり、より多くのメモリを消費します。GCはメモリ使用量が減少するため機能していますが、全体的にはプロセッサが機能するにつれて上昇します。

インデクサーを高速化するためにできることはありますか?なぜ着実にパフォーマンスが低下しているのですか?開始が非常に速いため、nhibernateやクエリではないと思います。私たちはここで本当に途方に暮れています。

ありがとう

4

3 に答える 3

3

Ayendeは、ほんの数週間前に(ステートレスセッションとカスタムIList実装を使用して)これを実行することについて投稿しました。

http://ayende.com/Blog/archive/2010/06/27/nhibernate-streaming-large-result-sets.aspx

これは、少なくともレコードの取得を高速化し、メモリ使用量を最小限に抑えるために必要なもののように聞こえます。

于 2010-07-28T17:12:55.127 に答える
0

すべての通話に同じセッションを使用していますか?その場合、ロードされたエンティティをキャッシュし、それらをループして、Flushが呼び出されたときにフラッシュが必要かどうかを確認します(これはFlushModeによって異なります)。アイテムのすべてのページに新しいセッションを使用するか、FlushModeを変更します。

基準を使用する場合は、SQL結合を使用して特定のプロパティをプリフェッチするように指定できます。これにより、データの読み取りが高速化される場合があります。私は通常、Linq-to-NHibernateよりもcritiera apisを信頼しています。これは、すべての呼び出しに対して何を行うかを実際に決定するからです。

于 2010-07-28T16:40:40.267 に答える
0

インデックス作成のためにSolrに移動することになりました。おそらく実装が原因で、効率的にインデックスを作成することができませんでした。

参考のために:

http://lucene.apache.org/solr/

http://code.google.com/p/solrnet/

于 2010-08-26T20:36:19.250 に答える