5

製品、カテゴリ、pro_cat_link の 3 つのテーブルがあります。製品は、テーブル pro_cat_link を介して 1 つまたは複数のカテゴリにリンクできます。

私のクエリは、一連のカテゴリに一致するすべての製品を検索するという問題に答える必要があります。例: 「黄色 AND 果物 AND スイーツ」であるすべての製品を検索します。

SO でこの問題を調査すると、現在使用している解決策しか見つかりませんでした: 複雑な SQL クエリ - 複数の異なる外部キーに一致する項目を見つける

私の場合、クエリは次のようになります。

SELECT products.id, COUNT(DISTINCT categories.id) as countCat
FROM products
INNER JOIN pro_cat_link ON (pro_cat_link.product_id = products.id)
WHERE pro_cat_link.category_id IN (3,6,8,10)
GROUP BY product.id
ORDER BY product.date DESC
HAVING countCat = 4

つまり、カテゴリ ID (3、6、8、10) のいずれかに一致するすべての製品を選択し、正確に 4 つのカテゴリが一致する製品のみを保持します。

これはうまく機能しますが、COUNT()、GROUP BY、ORDER BY によって適切なインデックス作成が非常に制限されるため、パフォーマンスの問題が発生しています。その問題を解決するためのより良い方法を考えられる人はいますか?

4

2 に答える 2

2

その情報をどこかに保存すれば、グループ化とカウントのパフォーマンスの問題を解消できます。Products という名前の列を追加して、total_categoriesその製品が参加しているカテゴリの数を示すことができます。その後、単にwhere total_categories = 4. このフィールドを常に正しく更新する必要があるため、製品のカテゴリが頻繁に変更される場合、これを維持するのがより困難になる可能性があります。その後、それをアプリケーション コードで行うか、トリガーで行うか、ストアド プロシージャで行うかを決定する必要があります。 ...

通常、このようなメタデータをテーブルに直接保存することはあまり良い考えではないと思いますが、パフォーマンスが本当に悪い場合は、検討する価値があるかもしれません.

于 2012-06-22T14:10:25.183 に答える
1

カテゴリが多すぎない場合は、列数を追跡する代わりに、カテゴリを表すビット文字列を使用できます (つまり、位置 i の 1 は製品がカテゴリ i にあることを意味し、0 は製品がカテゴリ i にあることを意味します)。カテゴリにはありません)。次に、カテゴリのグループを検索するときに、その検索用のビットAND文字列と、この文字列を含むすべてのカテゴリ文字列を生成します。正しいカテゴリにあるものは、検索文字列を答えとして生成します。

たとえば、10 個のカテゴリがあるとします。Item1 はカテゴリ1, 3, 5, 6, 8, 10に属しているため、そのカテゴリ文字列は1010110101です。Item2 はカテゴリ1, 2, 4, 6, 8, 10に属しているため、そのカテゴリ文字列は1010101011です。3、6、8、および 10 を検索すると、文字列 が生成されますs = 1010100100Item1 & s = 1010100100 = s. Item2 & s = 1010100000 <> s.

さらに、文字列として保存する必要はありません。実際の 10 進数に相当するものとして保存できます。したがって、Item1、Item2、および s は、それぞれ 693、683、および 676 です。 693 & 676 = 676、しかし683 & 676 = 672。次に、製品をカテゴリ i に追加する場合は、カテゴリ番号を 2^(i - 1) だけ更新し、カテゴリ i から削除する場合は、2^(i - 1) を減算します。

もちろん、MySQL int のビット数よりも多くのカテゴリがある場合、これはまったく機能しません。また、彼の回答で FrustratedWithFormsDes が指摘しているように、これは pro_cat_link とこのテーブルの両方を更新するすべての問題を引き起こします (もちろん、pro_cat_link の使用目的によっては、完全に解消される可能性があります)。さらに、カテゴリの数字が変わると、すべてを更新する必要があります。

于 2012-06-22T15:04:11.480 に答える