5

次の2つの指標を作成すると

ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address);
ALTER TABLE requests ADD INDEX is_cached(exec_date, cached);

の出力show index from requestsは次のとおりです

Table       Non_unique  Key_name    Seq_in_index    Column_name Collation   Cardinality Sub_part    Packed  Null    Index_type  Comment Index_comment
requests    1           daily_ips   1               exec_date   A           413         NULL    NULL    YES BTREE       
requests    1           daily_ips   2               ip_address  A           218334      NULL    NULL    YES BTREE       
requests    1           is_cached   1               exec_date   A           165         NULL    NULL    YES BTREE       
requests    1           is_cached   2               cached      A           165         NULL    NULL    YES BTREE       

私は次のクエリを持っています

EXPLAIN SELECT exec_date,
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)  / SUM(1) cached_no,
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)  / SUM(1) cached_yes
FROM requests
GROUP BY exec_date;

id  select_type table   type    possible_keys   key         key_len ref rows    Extra
1   SIMPLE  requests    index   NULL            daily_ips   263 NULL    436695  

is_cachedただし、クエリオプティマイザにインデックスの代わりにインデックスを使用するように強制したいと思いdaily_ipsます。

インデックスを削除しdaily_ipsて再度追加すると

ALTER TABLE requests DROP INDEX daily_ips;
ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address);

次に、同じEXPLAINステートメントを実行すると、クエリオプティマイザがis_cachedインデックスを選択します。

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  requests    index   NULL    is_cached   6   NULL    440493  Using index

クエリオプティマイザが追加された順序に基づいてインデックスを選択することは予想される動作ですか?

クエリオプティマイザに使用するインデックスを指示するにはどうすればよいですか?

4

2 に答える 2

2

クエリで実行するインデックスを指定できます。

これを試して:

EXPLAIN SELECT exec_date,
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)  / SUM(1) cached_no,
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)  / SUM(1) cached_yes
FROM requests USE INDEX(is_cached)
GROUP BY exec_date;

USE INDEXとの違いFORCE INDEX

USE INDEX(index_list)を指定することにより、名前付きインデックスの1つのみを使用してテーブル内の行を検索するようにMySQLに指示できます。代替構文IGNOREINDEX(index_list)を使用して、特定の1つまたは複数のインデックスを使用しないようにMySQLに指示できます。これらのヒントは、MySQLが可能なインデックスのリストから間違ったインデックスを使用していることをEXPLAINが示している場合に役立ちます。

FORCE INDEXを使用することもできます。これは、USE INDEX(index_list)のように機能しますが、テーブルスキャンは非常にコストがかかると想定されています。つまり、テーブルスキャンは、指定されたインデックスの1つを使用してテーブル内の行を検索する方法がない場合にのみ使用されます。

アップデート

このクエリを試してください:

SELECT exec_date, 
       100 * SUM(IF(cached = 0, 1, 0)) / SUM(1) cached_no, 
       100 * SUM(IF(cached = 1, 1, 0)) / SUM(1) cached_yes 
FROM (SELECT exec_date, IF(cached = 'no', 0, 1) cached 
      FROM requests GROUP BY exec_date) AS A 
于 2012-11-26T06:27:11.970 に答える
2

1つのインデックスを他のインデックスに強制するには、FORCE INDEXディレクティブを使用できます。

EXPLAIN SELECT exec_date,
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)  / SUM(1) cached_no,
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)  / SUM(1) cached_yes FROM requests FORCE INDEX(`is_cached`) GROUP BY exec_date;

MySQLオプティマイザは、スキャンする行が少ないインデックスを選択します。この場合、このカウントは両方のインデックスで非常に近くなります(436695対440493)。

于 2012-11-26T06:27:56.960 に答える