2016-10-19 10 views
0

私はいくつかの引数を取るストアドプロシージャを持っています。入力として受け取った引数の値に基づいて、特定の順序でソートされた結果を返す必要があります。私が問題に直面しているのは、switch-caseブロックで1つのクエリをorder by節に記述しようとすると、クエリはインデックスを使用しません。サンプル構造は次のとおりです。MySql:条件付き並べ替えを処理する方法


create table test_table(
f1 int, 
f2 int, 
f3 int, 
key (f1), 
key(f2) 
); 

-- now insert 2M rows in the table 

-- query #1 
mysql> explain select f1, f2 from test_table order by f1 desc limit 1000; 
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra | 
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+ 
| 1 | SIMPLE  | test_table | index | NULL   | f1 | 5  | NULL | 1000 | NULL | 
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+ 
1 row in set (0.00 sec) 

-- query #2 
mysql> explain select f1, f2 from test_table order by f2 desc limit 1000; 
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra | 
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+ 
| 1 | SIMPLE  | test_table | index | NULL   | f2 | 5  | NULL | 1000 | NULL | 
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+ 
1 row in set (0.00 sec) 

set @a = 1, @b = 'd'; 

--query #3 
mysql> explain select f1, f2 from test_table 
    order by 
    case when @a = 1 and @b = 'd' then f1 
     when @a = 2 and @b = 'd' then f2 end desc, 
    case when @a = 1 and @b = 'a' then f1 
     when @a = 2 and @b = 'a' then f2 end asc 
     limit 1000; 
+----+-------------+------------+------+---------------+------+---------+------+---------+----------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+------------+------+---------------+------+---------+------+---------+----------------+ 
| 1 | SIMPLE  | test_table | ALL | NULL   | NULL | NULL | NULL | 1995435 | Using filesort | 
+----+-------------+------------+------+---------------+------+---------+------+---------+----------------+ 
1 row in set (0.00 sec) 

説明1または2を参照すると、出力が期待どおりに表示されます。しかし、私はランタイムにソート列を決定しようとすると、インデックスのいずれかを使用することはできません。 #3を達成するための1つの代替策は、if-elseブロックを作成して個々のクエリを書くことですが、複数の可能性がある場合は醜い結果になります。上記の例では、異なる順序の異なる4つのブロックにつながります。

私の質問: 質問3を実行するための別の方法とその賛否両論は何ですか?

+0

いいえ、そこに個々のquerysを書き込む方法はありません(または、PHPや動的SQLで行う場合は、少なくとも個別のエンディングがあります)。私はそれがあなたの現在のクエリよりも醜いか読めないように見えるとは思わない。そして、あなたのクエリはインデックスを使うことができないだけでなく、1つではなく2つのカラムで注文します(これらのうちの1つは定数 'null'ですが、mysqlはこれでもソートする必要があります)。擬似定数のように見えても、すべての行について評価されます。 – Solarflare

+0

必要に応じて、「NOT NULL」と言ってください。明示的な「主キー」を持っています。 'INDEX(f1、f2)'を使ってください。しかし、あなたの 'SELECT'が_real_ selectでない場合、このアドバイスは役に立ちません。 –

+0

おそらく、あなたは 'when @a = 2'を意味しましたか? (私はその変更を行いました) –

答えて

0

SELECTのバリエーションを処理する最善の方法は、アプリケーションコードで動的にクエリを構築することです。

一般的な例は、エンドユーザーがさまざまなことを指定できる(またはしない)場合です。アプリケーションは指定されたものでWHERE節を構築できます。ユーザーの入力に応じてINまたはBETWEEN節を作成することもできます。

あなたのケースはORDER BYと関係があります。この場合も、アプリケーションコードは、目的のORDER BYを簡単に構築できます。これにより効率的なクエリが作成されます。

悲しいことに、これに代わるSQL内には構造体がありません。

関連する問題