LoginSignup
2
1

More than 3 years have passed since last update.

【備忘録】PHPで複数検索条件があるSQLを投げるときのクエリ作成方法

Posted at

概要

  • 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秒くらいで返ってくるようになりました。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1