次のようなものを使用して、1つの条件で複数の行を選択できます。
SELECT `Col`, `Col2` FROM `Table` WHERE `Col3` IN (?, ?, ?, ?, ?);
# This selects 5 rows
複数の条件(すべての整数が等しい演算)がある場合、これをどのように実行できますか?
クエリがチェックする必要がある3つの条件があり、これらの3つすべてが複合主キーを構成します。
1つのクエリで10〜100行を選択します(ほとんどの場合10行のみです)。パフォーマンスの点で高速でなければなりません。このため、複数のクエリを使用することはお勧めできません。
CREATE TABLE
ステートメントは:
CREATE TABLE `Table Name` (
`X` smallint(6) unsigned NOT NULL,
`Y` smallint(6) unsigned NOT NULL,
`Z` smallint(6) unsigned NOT NULL,
`Data` varchar(2048) NOT NULL DEFAULT '',
PRIMARY KEY (`X`,`Y`,`Z`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
複数のクエリを使用すると、次のように実行できます。
SELECT `One`, `Two` FROM `Table` WHERE `X` = ? AND `Y` = ? AND `Z` = ?;
SELECT `One`, `Two` FROM `Table` WHERE `X` = ? AND `Y` = ? AND `Z` = ?;
SELECT `One`, `Two` FROM `Table` WHERE `X` = ? AND `Y` = ? AND `Z` = ?;
# This selects 3 rows but I don't want to make 3 calls to the database server for that
これを1つのクエリで実行するための2つの基本的な構文オプションと、クエリで値を送信するか、最初にテーブルにロードするかに関する2つのオプションがあります。
通常のAND
/OR
(括弧はここでは冗長ですが、OR
がより複雑になる場合に備えて、WHERE
と一緒に使用することをお勧めします):
WHERE ( ( x = ? AND y = ? AND z = ? )
OR ( x = ? AND y = ? AND z = ? )
...
OR ( x = ? AND y = ? AND z = ? )
)
「行コンストラクター」付きのコンパクトIN
:
WHERE (x,y,z) IN ((?,?,?), (?,?,?), ...)
(一時)テーブルとJOIN
にトリプレットをロードします。
CREATE (TEMPORARY) TABLE tmp_table
--- ;
INSERT INTO tmp_table (x,y,z)
VALUES (?,?,?), (?,?,?), ... ;
SELECT t.*
FROM my_table AS t
JOIN tmp_table AS tmp
ON ( t.x = tmp.x AND t.y = tmp.y AND t.z = tmp.z )
;
または:
ON (t.x, t.y, t.z) = (tmp.x, tmp.y, tmp.z)
最初の2つのオプションは同等ですが、バージョンによっては効率が異なる場合があります。タプル(行コンストラクター)を含むIN
のこの構文は、古いバージョンではインデックスを最も効果的に使用しません。 5.7では、オプティマイザーは2つの構文を同等として識別します( MySQLドキュメント:行コンストラクター式の最適化 を参照)。 テスト!
いくつかのパラメーター/トリプレットを照会する場合は、テーブルを使用する他の方法が適している場合があります。 (temp)テーブルにインデックスを付けることもできます。 テスト!
したがって、基本的なアドバイスは、バージョン/構成/セットアップでtestを実行することです。テーブルには、予測されたサイズと同様のサイズがあり、さまざまな数のテーブルがあります。パラメーター。
テストする価値があるかもしれないもう2つの方法:
単純なUNION ALL
。パラメータだけが異なる複数の同一のクエリを実行したいだけなので。 1つの欠点は、基本的なクエリが複雑で、チェックするトリプレットが多数ある場合、クエリが非常に長く、見苦しく見えることです。
SELECT t.* FROM my_table AS t
WHERE ( x = ? AND y = ? AND z = ? ) UNION ALL
SELECT t.* FROM my_table AS t
WHERE ( x = ? AND y = ? AND z = ? ) UNION ALL
---
SELECT t.* FROM my_table AS t
WHERE ( x = ? AND y = ? AND z = ? ) ;
派生テーブルの使用(UNION ALL
)JOIN
バリエーション。これは、派生テーブルを具体化してインデックスを作成できる最適化(5.5または5.6で追加されたもの)を使用する場合があります。
SELECT t.*
FROM my_table AS t
JOIN
( SELECT ? AS x, ? AS y, ? AS z UNION ALL
SELECT ?, ?, ? UNION ALL
---
SELECT ?, ?, ?
)
AS tmp
ON ( t.x = tmp.x AND t.y = tmp.y AND t.z = tmp.z )
;
MariaDBへのメモ。行コンストラクター式の最適化は機能しません!私のバージョンは10.1.24ですが、10.2のメモにも記載されていません。 PRIMARYではテストしませんでしたが、UNIQUEおよび通常のINDEXではテストしました。
また、AND/ORを使用していて、クエリの長さが長くなっている場合(約1200の条件-正確な数値ではありません)、クエリアナライザーは適切なインデックスの選択に失敗するため、クエリにFORCE INDEX句を追加する必要があります。
長いクエリ-悪い分析。行コンストラクターはその日を救ったでしょう。