1

ネストされたループ結合アルゴリズムを説明する記事を読んでいますが、ネストされた選択の実際の動作原理を正確に理解していません。記事で提供されている例を次に示します。

この例では、姓が「WIN」で始まる従業員を検索し、これらの従業員のすべての SALES をフェッチします。

ネストされたループ結合を表すクエリは次のとおりです。

select employees0_.subsidiary_id as subsidiary1_0_
       -- MORE COLUMNS
from employees employees0_ 
where upper(employees0_.last_name) like ?;

select sales0_.subsidiary_id as subsidiary4_0_1_
         -- MORE COLUMNS
from sales sales0_
where sales0_.subsidiary_id=? 
  and sales0_.employee_id=?;

select sales0_.subsidiary_id as subsidiary4_0_1_
         -- MORE COLUMNS
from sales sales0_
where sales0_.subsidiary_id=? 
  and sales0_.employee_id=?;

ご覧のとおり、最後の 2 つのクエリは完全に同じです。これは私が混乱したものです。最初の 2 つのクエリを生成するだけでは十分ではないのはなぜですか? なぜ 3 番目のものを生成する必要があるのでしょうか。

4

2 に答える 2

1

貼り付けたコードは、参照されている記事の例であり、アンチパターンであることを覚えておいてください。

つまり、クエリはパラメーター化されているため、実際には同一ではありません。各クエリの最初の 2文字はパラメータであり、for ループの反復ごとに?異なる値に置き換えられます。subsidiary_id

于 2015-09-06T15:27:11.250 に答える
0

3 番目のクエリを生成する必要はありません。SQL クエリを手動で作成すると、取得したすべての従業員のすべての売上を 1 つのクエリとして読み込むことができます。しかし、「N+1 クエリ」アンチパターンは、プログラム コードが記事のように見える場合に発生します。

for (Employees e: emp) {
  // process Employee
  for (Sales s: e.getSales()) {
    // process sale for Employee
  }
}

そのコードe.getSales()メソッドでは、1 人の従業員のデータをロードします。ORM には販売データをロードする必要がある従業員の完全なリストがないため、この方法では他のすべての従業員の販売データをロードするのに十分な情報がありません。そのため、ORM は各従業員の売上データを個別のクエリでロードする必要があります。

一部の ORM は、「N+1 クエリ」の問題を自動的に回避できます。たとえば、PonyORM (Python で記述) では、この記事のコードは次のようになります。

# the first query loads all necessary employees
employees = select(e for e in Employee if e.lastName.startswith('WIN'))

for e in employees:
    # process Employee
    for sale in e.sales:
        # process sale for Employee

プログラムが従業員クエリのループを開始すると、PonyORM は必要なすべての従業員を一度にロードします。最初の従業員の販売アイテムが要求されると、PonyORM はこの従業員に対してのみそれをロードします (ORM は私たちの意図を認識せず、おそらく最初の従業員の販売データのみが必要であると想定するため)。しかし、2 番目の従業員の売上データが要求されると、PonyORM は「N+1 クエリ」アンチパターンに気付き、N 個の従業員オブジェクトがメモリに読み込まれていることを確認し、残りのすべての従業員の売上を 1 つのクエリで読み込みます。この動作はヒューリスティックと見なすことができます。for-loop に含まれる場合、いくつかの余分な販売オブジェクトをロードする可能性がありますbreak手術。ただし、通常、このヒューリスティックはクエリの数を大幅に削減できるため、パフォーマンスが向上します。通常、余分なデータをロードすることは問題ではありませんが、サーバーへのラウンドトリップ数を減らすことがより重要です。

于 2015-09-07T11:56:28.030 に答える