4

テーブル内の複数の列を持つ用語を検索するための SQL クエリを作成する最適かつ最適化された方法は何ですか?

たとえば、製品のテーブルがあります。

id | title   | color_id
-------------------
 1 | Dress   | 1 (red)
 2 | T-shirt | 3 (blue)
 3 | Pants   | 2 (green)
 4 | Socks   | 1 (red)
 5 | Dress   | 2 (green)
 6 | Shoes   | 2 (green)
 7 | Pants   | 3 (blue)

そして色の表:

id | color
----------
 1 | Red
 2 | Green
 3 | Blue

また、ユーザーがRed dressという用語を入力した場合、結果としてProductid1で表示される必要があり、ユーザーが単にRedProductsと入力した場合、結果としてid1および で表示される必要があります4

更新:dress redまたはのようないくつかの入力があるかもしれませred blueん。

表の実際のバージョンはもっと複雑ですが、最も簡単な方法で説明しようとしました。

4

3 に答える 3

2

「うまくいく」単純な解決策は次のとおりです。

SELECT *
FROM products
JOIN colors ON colors.id = products.color_id
WHERE 
    ( title = "red" AND color = "dress" ) OR
    ( color = "red" AND title = "dress" )

この条件は、オプティマイザーがそれ自体に気付かないほど愚かである場合、より適切に機能する可能性があります。

WHERE 
    ( title = "red" OR title = "dress") AND
    ( color = "red" OR color = "dress")

問題にさらにプロパティ (「タイトル」と「色」以外) を追加し、ストレージが問題にならない場合は、すべてのテキスト プロパティを 1 つのVARCHAR列にマージ (および複製) し、フルテキストを実行することをお勧めします。この列で検索します。

CREATE TABLE products_properties (
    product_id INT NOT NULL PRIMARY KEY,
    properties VARCHAR (255),
    FOREIGN KEY fk_product (product_id) REFERENCES products(id),
    FULLTEXT ftx_properties (properties)
);

検索は非常に簡単になります。

SELECT products.*, colors.*
FROM products
JOIN colors ON colors.id = products.color_id
JOIN products_properties AS pp ON pp.product_id = products.id
WHERE MATCH(properties) AGAINST ("+red +dress")

これは、この特定の例では明らかに意味がありませんが、プロパティが多いほど、クエリが高速化されます。この非正規化には、products_propertiesテーブルを維持するための複雑さが増すという犠牲も伴います。

今、問題は本当に毛むくじゃらになります

  • 「赤青」などの正規化されていない入力を処理する必要がある
  • 両方のカテゴリに属する​​単語を持ち (例: "red" も有効な布のタイトルである場合)、それらを区別したい場合 (例: "red blue" のようなクエリは、"red" という名前で色が "blue" の布を返します)

しかし、これはあなたの質問の範囲外のようです。

于 2013-06-22T22:55:38.290 に答える
1

SQL でこれを行う場合、通常、クエリを実行する前にクエリを個々の単語に分解し、単語の数に基づいて動的にクエリを作成します。

したがって、あなたの例では、クエリは次のようになります。

SELECT * 
FROM products p
JOIN colors c ON c.id = p.color_id
WHERE 
p.title LIKE '%red%' OR
c.color LIKE '%red%' OR
p.title LIKE '%dress%' OR
c.color LIKE '%dress%'

ただし、多数のテーブルがある場合、これはかなり複雑になり始める可能性があります。また、使用可能なインデックスがほとんどないため、あまり効率的ではありません。

より良い解決策は、Lucene のような専用のテキスト インデックス作成製品を使用することです (しかし、それはまったく別の問題です..)

于 2013-06-20T19:54:03.043 に答える
1

私の考えは、次のようなクエリを使用することです。

set @search = 'red dress';

SELECT *
FROM
  products INNER JOIN colors
  ON products.color_id = colors.id
WHERE
  (FIND_IN_SET(title, REPLACE(@search, ' ', ','))>0)+
  (FIND_IN_SET(color, REPLACE(@search, ' ', ','))>0) =
  LENGTH(@search)-LENGTH(REPLACE(@search, ' ', ''))+1;

FIND_IN_SET 内の 2 つの置換は、コンマで区切られたプロパティのリストを作成するために使用されます。

red,dress

title次に、がこのセットに含まれているかどうかを確認しています。存在する場合、次の値:

(FIND_IN_SET(title, REPLACE(@search, ' ', ','))>0)

それ以外の場合は 1、0 と評価されます。同じですcolor

検索文字列内のプロパティの数は、次のように計算できます。

LENGTH(@search)-LENGTH(REPLACE(@search, ' ', ''))+1

(はい、それは汚いトリックです!)。一致するプロパティの数が @search 文字列内のプロパティと同じ場合、その行が返されます。パフォーマンスが低下することに注意してください。

フィドルはこちらです。

于 2013-06-23T21:41:13.837 に答える