4

この質問はおそらくすでに何千回も聞かれているような気がするので、答えられていたら申し訳ありません。もしそうなら、誰かが私に正しい投稿/リンクを教えてもらえますか?

私がやろうとしているのは、サイトのファセット ナビゲーションを構築することです。これは MySQL を使用しており、私が使用しているテーブルの大まかなスケッチは次のとおりです。

製品:
- ID
- 題名
- 説明
属性:
- 製品番号
- 名前
- 価値
カテゴリ:
- ID
- 名前
products_to_categories:
- 製品番号
- カテゴリ ID

私がやりたいことは、カテゴリにいるときに利用可能な属性のリストを表示し、それらの属性ごとに 1 つ以上の値を選択できるようにすることです。例として、Office Depot の次のページを見てください: http://www.officedepot.com/a/browse/binders/N=5+2177/

これまで、複数の属性をフィルタリングするために多くの結合を使用してきました。

SELECT products.*、a_options.*
FROM products_to_categories AS PC、製品、
attributes AS a_options, /* 引き続き改良できる属性/値のペアのリスト */
attributes AS a_select1 /* 最初に選択された属性 */
attributes AS a_select2 /* 2 番目に選択された属性 */
...
WHERE pc.category_id = 1
AND products.id = pc.product_id
AND a_options.product_id = products.id
AND a_options.name != '色' AND a_options.name != 'サイズ'
AND a_select1.product_id = products.id
AND a_select1.name = 'Color' AND (a_select1.value = '青' OR a_select1.value = '黒')
AND a_select2.product_id = products.id
AND a_select2.name = 'Size' AND a_select2.value = '8.5 x 11'

基本的に、 と を使用しa_optionsて適用したフィルターのサブセットである製品のすべての属性を返します。したがって、Office Depot のバインダーの例を使用する場合、色に青または黒を選択し、サイズに「8.5 x 11」を選択した後、使用可能なすべての属性を表示したいと考えています。a_select1a_select2

次に、PHP コードを使用して重複を削除し、結果の属性を次のような配列に配置します。

属性[名前1] = (val1、val2、val3、...)
属性[名前2] = (val1、val2、val3、...)

クエリを高速化したり、より効率的に記述したりする方法はありますか? 属性テーブルの名前と値 (およびすべての ID 番号) にインデックスを設定しました。しかし、誰かがいくつかの属性を選択すると、クエリの実行が遅くなります。

事前にご協力いただきありがとうございます、
Sridhar

4

2 に答える 2

8

「次に、PHPコードを使用して重複を削除します」

その場合、スケーリングは行われません。

http://www.amazon.com/Data-Warehouse-Toolkit-Techniques-Dimensional/dp/0471153370を読んだ後、ファセットとフィルタリングメカニズムをノンストップで展開していました。

基本的な考え方は、スタースキーマを使用することです。

ファクトを格納するファクトテーブルを作成します

customerid | dateregisteredid | datelastloginid
1 | 1 | 1
2 | 1 | 2

属性を格納するディメンションテーブルに外部キーを使用します

date_registered
Id | weekday | weeknumber | year | month | month_year | daymonth | daymonthyear
1 | Wed      | 2            | 2009 | 2   |2-2009      | 4        | 4-2-2009

次に、使用している「パラダイム」の日付に関係なく、そのディメンションテーブルからすべてのIDを取得して

 select * from the fact table where the fact.dateregisteredid is IN( ... the ids from the date dimension table that represent your time period)

データのこれらの「インデックス付きビュー」は別のデータベースに存在する必要があり、本番環境でのオブジェクトへの変更は、分析システムでの再インデックスのためにそのレコードをキューに入れる必要があります。大規模なサイトでは、ピーク時以外の時間にレコードをバッチ処理して、統計レポートアプリケーションが常に数時間または数日遅れる場合があります。アーキテクチャがそれをサポートしている場合、私は常にそれを秒単位に保つようにしています。

行数のプレビューを表示している場合は、かなりの最適化またはキャッシュを実装する必要があるかもしれません。

基本的に要約すると、データをコピーして非正規化します。この手法は、「データウェアハウジング」またはOLAP(オンライン分析処理)という名前で呼ばれます。

Oracleのような商用データベースを使用するより良い方法がありますが、スタースキーマはオープンソースのリレーショナルデータベースを持っている人なら誰でも利用できるようにします。

あなたは間違いなくツールキットを読むべきですが、彼はあなたにかなりの時間を節約することができる多くのことを話します。更新されたデータを処理し、レポートアプリケーションで監査履歴を保持するための戦略と同様です。彼はすべての問題について、それぞれが異なる状況に適用できる複数の解決策を概説しています。

簡単な方法をとらず、大量の不要な結合を使用しないと、数百万行までスケールアップする可能性があります。

于 2009-12-02T07:26:37.000 に答える
6

正規化されたデータベース テーブルに基づいてファセット テーブルを生成できます。
例えば:

> SELECT * FROM product_facet
product_id | facet_type | facet_value
1          | color      | blue
2          | color      | blue
3          | color      | green
4          | color      | yellow
1          | speed      | slow
2          | speed      | slow

次に、次のクエリを実行して、属性ごとの合計を取得します。

SELECT facet_type, facet_value, COUNT(facet_value) as total
FROM product_facet
GROUP BY facet_type, facet_value;

結果:

facet_type | facet_value | total
color      | blue        | 2
color      | green       | 1
color      | yellow      | 1
speed      | slow        | 2

基準で検索する場合、製品 ID に一致するファセット テーブルを選択できます。

SELECT facet_type, facet_value, COUNT(facet_value) as total
FROM product_facet
WHERE product_id in (SELECT product_id FROM products WHERE ... )
GROUP BY facet_type, facet_value;
于 2014-01-28T05:02:32.583 に答える