first_name
とに適切なインデックスがあってもlast_name
、それらを CONCAT すると意味がありません。
私が (何百万ものレコードにわたって) 良い結果を得たアプローチは、アプリケーション ロジックと SQL の組み合わせです。氏名が常にスペースで接続されると仮定すると、検索テキストを (アプリ レベルで) スペースで分割できます。検索テキストに含まれるスペースの数によって、実行するクエリの種類が決まります。
まず、両方の列にインデックスを追加します。
ALTER TABLE `sl_customers` ADD INDEX idx_name_search (`first_name`,`last_name`);
次に、スペースで区切られた名前のすべての順列を作成します。動作する php の例を次に示します。
$search_text = 'millhouse van houten';
$conditions = '';
$parts = explode(' ', $search_text);
for($i=count($parts); $i>=0; $i--){
$params[] = implode(' ', array_slice($parts, 0, $i)).'%'; //first name
$params[] = implode(' ', array_slice($parts, $i)).'%'; //last anme
$conditions .= '(`first_name` LIKE ? AND `last_name` LIKE ?) OR ';
}
$conditions = substr($conditions, 0, -4); //trim the last OR
$query = 'SELECT `first_name`, `last_name` FROM `customer` WHERE '.$conditions;
次のようなクエリになります。
SELECT `first_name`, `last_name` FROM `customer` WHERE
(`first_name` LIKE ? AND `last_name` LIKE ?) OR
(`first_name` LIKE ? AND `last_name` LIKE ?) OR
(`first_name` LIKE ? AND `last_name` LIKE ?) OR
(`first_name` LIKE ? AND `last_name` LIKE ?);
および次のようなパラメーター
[0] => millhouse van houten%
[1] => %
[2] => millhouse van%
[3] => houten%
[4] => millhouse%
[5] => van houten%
[6] => %
[7] => millhouse van houten%
これにより、次のような組み合わせのセットが検索されます。
first_name | last_name
-------------------------------------------------
millhouse van houten% | %
millhouse van% | houten%
millhouse% | van houten%
% | millhouse van houten%
ほとんどの場合、実際には氏名に含まれるスペースは 1 つだけであるため、私の例よりも比較対象が少なくなることに注意してください。
ワイルドカードを使用したい場合もありますが、インデックスを ( first_name
, last_name
) ANDのままにしてlast_name
おけば、常にインデックスを効果的に使用できます。比較の開始時にワイルドカードをLIKE
使用すると、インデックスの使用が停止します。
長い回答で申し訳ありません - アイデアをできるだけ明確にしたかっただけです。