概要
- PHPからDBに複数条件のあるクエリを投げるときを想定
- PHPではWEB画面があり、ユーザーからデータの期間と検索対象となるファイルがアップロードされる
- ファイルに書かれた行数によってSQLクエリが変動するのでそれを補う方法を書く
PHP
- 既にDBには接続されているものとする
- テーブルは
ID | URL | DATE |
---|---|---|
id | url | date |
- アップロードしたファイルの中身(URL)は別途配列として
$uploadUrlList
に格納
$countUrlList = count($uploadUrlList);
function createSQL($countUrlList)
{
if (!is_int($countUrlList)) {
trigger_error("Only Integer", E_USER_ERROR);
}
$sql = <<<EOM1
SELECT
ID,
URL
FROM
TABLE_NAME
WHERE
EOM1;
for ($i = 0; $i < $countUrlList; $i++) {
if ($i == 0) {
$sql .= "(URL LIKE :sqlUrlList{$i} OR ";
} elseif ($i == $countUrlList-1) {
$sql .= "URL LIKE :sqlUrlList{$i});";
} else {
$sql .= "URL LIKE :sqlUrlList{$i} OR ";
}
}
$sql .= <<<EOM2
AND
DATE
BETWEEN :sqlPeriodFrom
AND :sqlPeriodTo
EOM2;
return $sql;
}
$conn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$sql = $sql_func->createSQL($countUrlList);
$prepareSqlStatement = $conn->prepare($sql);
$prepareSqlStatement->bindValue(':sqlPeriodFrom', $periodFrom, PDO::PARAM_STR);
$prepareSqlStatement->bindValue(':sqlPeriodTo', $periodTo, PDO::PARAM_STR);
for ($i = 0; $i < $countUrlList; $i++) {
$prepareSqlStatement->bindValue(":sqlUrlList{$i}", $uploadUrlList[$i], PDO::PARAM_STR);
}
ちなみに対象のテーブルは当時500万行くらいあったのですが、URLとDATEにインデックスがありませんでした。
当時は、期間指定で抽出したデータをCSVに吐き出し、URLリスト(アップロードしたファイル)とでgrep -E
で抽出していました。
これでは1時間くらいかかってしまいます。
そこでURLとDATEにマルチカラムインデックス貼ることにし上記のようなクエリにした結果30秒くらいで返ってくるようになりました。