web-dev-qa-db-ja.com

MySQLにすべてのインデックスを強制的に強制するにはどうすればよいですか?

FORCEインデックスに関する記事を読みましたが、MySQLに_IGNORE ALL_インデックスを強制するにはどうすればよいですか?

SELECT * FROM tbl IGNORE INDEX(*)を試しましたが、うまくいきませんでした。

なぜ私(および他の人)がこれを行う必要があるのか​​については、たとえば、次のようにtldでリファラー統計を要約する必要がありました。

_SELECT 
    count(*) as c, 
    SUBSTRING
    (
        domain_name, 
        LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
    ) as tld
FROM `domains_import` 
    IGNORE INDEX(domain_name)
GROUP BY tld
ORDER BY c desc
LIMIT 100
_

...しかし、どのインデックスが定義されているかを常に確認するか、Explainを使用してどのインデックスを使用するかを決定する必要があります。単純に_IGNORE INDEX ALL_を記述し、単に気にしないのは非常に便利です。

誰かが構文やハックを知っていますか? (MySQL定義テーブルを介した数十行は、実際にはショートカットではありません)。

チャットディスカッション から追加:

Bechmark:

  • インデックスなし= 148.5秒

  • インデックス= 180秒で、まだデータの送信で実行中SSDアレイは非常に強力であるため、データキャッシュはほとんど気にしません...

ベンチマークの定義:

_CREATE TABLE IF NOT EXISTS `domains_import` (
`domain_id` bigint(20) unsigned NOT NULL,
`domain_name` varchar(253) CHARACTER SET ascii COLLATE ascii_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `domains_import`
ADD PRIMARY KEY (`domain_id`),
ADD UNIQUE KEY `domain_name` (`domain_name`);

ALTER TABLE `domains_import`
MODIFY `domain_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT;
_

InnoDB、インデックス(USE INDEX()または類似のものなし)を使用したテストが250秒間実行されていますが、それを強制終了しました。

12
mvorisek

なぜこれが必要なのかは明確ではありませんが、ヒントUSE INDEX ()を使用して、オプティマイザにインデックスを使用しないように指示できます。 MySQLのドキュメントから: index hints

これは、構文的には[省略index_listfor USE INDEXに対して有効です。これは、[インデックスを使用しない]を意味します。]FORCE INDEXまたはIGNORE INDEXのindex_listを省略すると、構文エラーになります。

クエリは次のようになります。

SELECT count(*) AS c, 
       substring_index(domain_name, '.', -1) AS tld
FROM domains_import 
       USE INDEX ()        -- use no indexes
GROUP BY tld
ORDER BY c DESC
LIMIT 100 ;

補足:複雑な表現:

SUBSTRING(domain_name, LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2) 

4つの関数呼び出しから1に簡略化できます。

SUBSTRING_INDEX(domain_name, '.', -1)
24
ypercubeᵀᴹ

WHERE 1=1を埋め込むこともできます

SELECT 
    count(*) as c, 
    SUBSTRING
    (
        domain_name, 
        LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
    ) as tld
FROM `domains_import` 
WHERE 1=1
GROUP BY tld
ORDER BY c desc
LIMIT 100

ypercubeがちょうど私に尋ねた

ローランド、MySQLのオプティマイザーは非常に馬鹿げているので、単純な常に真の条件ではインデックスの使用が禁止されますか?

はい、しかしあなたはMySQLに本当にばかげたクエリを与えました。 1=1はクラスター化インデックスに戻ります。それにもかかわらず、別の方法がありますが、オプティマイザに対して少し悪意がある必要があります。

SELECT 
    count(*) as c, 
    SUBSTRING
    (
        domain_name, 
        LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
    ) as tld
FROM `domains_import` 
WHERE domain_name = domain_name
GROUP BY tld
ORDER BY c desc
LIMIT 100

domain_nameの各行の値がチェックされるため、これによりバスの下のすべてのインデックスが確実にスローされます。 domain_nameがインデックス付けされている場合は、まったくインデックス付けされていないWHERE column_name=column_nameの列を選択する必要があります。

ステージングサーバーの大きなテーブルでこれを試しました

mysql > explain SELECT COUNT(1) FROM VIDEO WHERE EMBEDDED_FLG=EMBEDDED_FLG;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | VIDEO | ALL  | NULL          | NULL | NULL    | NULL | 354327 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)

インデックスが選択されていません

2
RolandoMySQLDBA

次の2つのインデックスがあると仮定します。

ADD PRIMARY KEY (`domain_id`),
ADD UNIQUE KEY `domain_name` (`domain_name`);

次に、オプティマイザが何をするかは重要ではありません。本質的に同量のものをスキャンする必要があります。

ケース1:テーブルスキャンを実行します(またはdomain_idを使用します):(id、name)のペアをスキャンし、すべての名前を検索し、SUBSTRING..LOCATE、GROUP BY、最後にORDER BYを実行します。 GROUP BYとORDER BYは、おそらくそれぞれtmpテーブルとfilesortを必要とします。 EXPLAIN SELECT ...をチェックして、機能するかどうかを確認してください。

ケース2:(domain_nameの)インデックススキャンを実行します:そのインデックスには実際には(name、id)ペアが含まれます-InnoDBが暗黙的にPKをセカンダリキーの末尾に配置するためです。残りの処理はケース1に相当します。

1つcouldが異なる-2つのBTreeのサイズ。 SHOW TABLE STATUS LIKE domains_importを実行して、Data_length(ケース1の場合)およびIndex_length(ケース2の場合)を確認します。大きなBTreeは遅くなります。

別のことは異なる可能性があります-キャッシング。 innodb_buffer_pool_sizeの値は何ですか?どのくらいRAMありますか?データ(またはインデックス)をバッファプール内に含めることができますか(または、これがテーブル/インデックススキャンであるため、データの37%になりますか?) )当てはまる場合は、クエリを2回実行しますsecond時間は、ディスクにヒットしないため(キャッシュ)、約10倍高速になります。

これが1回限りのタスクである場合、SSDが役立ちます。そうでない場合は、テーブル全体をキャッシュできますが、buffer_poolがロードされた後は役に立ちません。

0
Rick James