@Jeremy SmithのFIND_IN_SET()の例に基づいて、結合を使用して実行できるため、サブクエリを実行する必要はありません。
SELECT * FROM table t
JOIN locations l ON FIND_IN_SET(t.e_ID, l.city) > 0
WHERE l.e_ID = ?
これは、テーブルスキャンを実行し、FIND_IN_SET()関数をすべて評価する必要があるため、パフォーマンスが非常に低いことが知られています。 table
の行の組み合わせ およびlocations
。インデックスを利用することはできず、それを改善する方法はありません。
悪いデータベース設計を最大限に活用しようとしているとあなたが言ったことは知っていますが、これがどれほど劇的に悪いかを理解する必要があります。
説明:最初、中間、または最後の頭文字が「J」である電話帳で全員を検索するように依頼したとします。とにかくすべてのページをスキャンする必要があるため、この場合、本の並べ替え順序が役立つ方法はありません。
LIKE
@fthiellaによって与えられた解決策には、パフォーマンスに関して同様の問題があります。インデックスを付けることはできません。
データベースの列に区切りリストを保存するのは本当に悪いですか? 非正規化されたデータを保存するこの方法の他の落とし穴について。
インデックスを保存するための補足テーブルを作成できる場合は、場所を都市リストの各エントリにマップできます。
CREATE TABLE location2city (
location INT,
city INT,
PRIMARY KEY (location, city)
);
考えられるすべての都市のルックアップテーブルがあると仮定します(table
に記載されている都市だけではありません)。 )マッピングを作成するために、非効率性に一度耐えることができます:
INSERT INTO location2city (location, city)
SELECT l.e_ID, c.e_ID FROM cities c JOIN locations l
ON FIND_IN_SET(c.e_ID, l.city) > 0;
これで、はるかに効率的なクエリを実行して、table
内のエントリを見つけることができます。 :
SELECT * FROM location2city l
JOIN table t ON t.e_ID = l.city
WHERE l.e_ID = ?;
これはインデックスを利用できます。ここで、locations
の行のINSERT/UPDATE/DELETEに注意する必要があります。 また、対応するマッピング行をlocation2city
に挿入します 。