4

重複の可能性:
Mysql クエリで整数を引用することの欠点?

MYSql データベースに Device という非常に単純なテーブルがあります。

+-----------------------------------+--------------+------+-----+----------------+
| Field                             | Type         | Null | Key | Extra          |
+-----------------------------------+--------------+------+-----+----------------+
| DTYPE                             | varchar(31)  | NO   |     |                |
| id                                | bigint(20)   | NO   | PRI | auto_increment |
| dateCreated                       | datetime     | NO   |     |                |
| dateModified                      | datetime     | NO   |     |                |
| phoneNumber                       | varchar(255) | YES  | MUL |                |
| version                           | bigint(20)   | NO   |     |                |
| oldPhoneNumber                    | varchar(255) | YES  |     |                |
+-----------------------------------+--------------+------+-----+----------------+

このテーブルには 100K を超えるレコードがあります。非常に単純なクエリを実行しています

select * from AttDevice where phoneNumber = 5107357058;

このクエリはほぼ 4 ~ 6 秒かかりますが、このクエリを以下のように少し変更すると、

select * from AttDevice where phoneNumber = '5107357058';

処刑されるのにほとんど時間はかかりません。phoneNumber 列が varchar であることに注意してください。前者の場合は時間がかかり、後者の場合は時間がかからない理由がわかりません。これら 2 つのクエリの違いは、一重引用符です。MYSQL はこれらを別の方法でクエリに処理しますか? もしそうなら、なぜですか?

編集1

次の出力を使用EXPLAINして取得しましたが、これら2つの結果を解釈する方法がわかりません。

mysql> EXPLAIN select * from AttDevice where phoneNumber = 5107357058;
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
| id | select_type | table     | type | possible_keys                         | key  | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | Device    | ALL  | phoneNumber,idx_Device_phoneNumber | NULL | NULL    | NULL | 6482116 | Using where |
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

mysql> EXPLAIN select * from AttDevice where phoneNumber = '5107357058';
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
| id | select_type | table     | type | possible_keys                         | key         | key_len | ref   | rows | Extra       |
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
|  1 | SIMPLE      |   Device  | ref  | phoneNumber,idx_Device_phoneNumber    | phoneNumber | 258     | const |    2 | Using where |
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
1 row in set (0.00 sec)

EXPLAIN クエリ出力に存在するキー、key_len、および行について説明してもらえますか?

4

5 に答える 5

3

1)「EXPLAIN」ありがとうございます。私たち全員(あなたを含む)は、問題はmysqlが整数を文字列に変換する必要があり、行ごとに変換する必要があることを知っていました。しかし、あなたの「EXPLAIN」はそれを証明しました。

2)EXPLAINに関する短い記事を次に示します。

*possible_keys *は、このクエリに適用されるインデックスを示し、キー は、実際に使用されたインデックスを示します-...最後に、rowsエントリは、MySQLが結果セットを見つけるために調べなければならなかった行数を示します。

Search value:   key:        type:  ref:   rows:  
-------------   ---         ----   ----   ----
5107357058      NULL        ALL    NULL   6482116
'5107357058'    phoneNumber ref    const  2

3)「ref」列は「インデックスと比較した列」です。2番目のケースでは、文字列リテラル( "constant")'5107357058'がキー"phoneNumber"と比較されました。最初のケースで、使用可能なキーがありませんでした(検索条件が完全に異なるタイプであったため)。したがって、「ref」はNULLでした。

4)「タイプ」列は「結合タイプ」です。「Ref」は、「インデックス値が一致するすべての行がこのテーブルから読み取られる」ことを意味します(この場合は2行)。「ALL」は「フルテーブルスキャン」を意味します。この場合、600万行を意味します。

5)「EXPLAIN」のmysqlドキュメントは次のとおりです。

于 2012-10-04T05:12:28.713 に答える
2

数値をオペランドとして使用する場合、varchar インデックスは使用できません。暗黙の型変換に関する優れたドキュメントからの抜粋です。

文字列列と数値を比較する場合、MySQL は列のインデックスを使用して値をすばやく検索することはできません。str_col がインデックス付きの文字列列の場合、次のステートメントでルックアップを実行するときにインデックスを使用できません。

SELECT * FROM tbl_name WHERE str_col=1;

これは、'1'、'1'、'1a' など、値 1 に変換される文字列が多数あるためです。

于 2012-10-04T01:53:24.180 に答える
2

電話番号を引用しないことで、MySQL をだまして悪い選択をさせました。検討:

  1. 列の定義は varchar です
  2. 最初の (引用符なしの) ケースでは、値を整数 (long) として指定しました。MySQL がこれを把握できると思っていたのですが、明らかにそうではなく、完全なテーブル スキャンを実行しました。
  3. 2 番目の (引用された) ケースでは、正しいデータ型 (文字) で検索キーを指定し、MySQL はフル テーブル スキャンよりもインデックスを選択しました。
于 2012-10-04T01:52:57.987 に答える
1

最初の例では、MySQLが数値をvarcharに変換する必要があると思います。2番目の例では、そうではありません。そこが違いだと思います。

于 2012-10-03T23:44:12.527 に答える
1

最初の例はテーブルを1つずつ調べ、もう1つの例はインデックスを使用します。

http://dev.mysql.com/doc/refman/5.0/en/show-columns.html
KeyがMULの場合、列内で特定の値を複数回出現させることができます。この列は、NULL値を含めることができる非一意のインデックスまたは一意の値のインデックスの最初の列です。

したがって、すべてのnull値をスキャンする代わりに、2番目のクエリはnull以外の値を排他的に探して処理を高速化します。

....おもう。

于 2012-10-04T01:07:20.320 に答える