sql >> データベース >  >> RDS >> Mysql

MySQLリレーショナル除算(INORではなくINAND)の実装におけるパフォーマンスの違いは何ですか?

    JOINにいくつかの改善を加えました バージョン;以下を参照してください。

    私はスピードのためにJOINアプローチに投票します。これが私がそれを決定した方法です:

    HAVING、バージョン1

    mysql> FLUSH STATUS;
    mysql> SELECT city
        ->     FROM us_vch200
        ->     WHERE state IN ('IL', 'MO', 'PA')
        ->     GROUP BY city
        ->     HAVING count(DISTINCT state) >= 3;
    +-------------+
    | city        |
    +-------------+
    | Springfield |
    | Washington  |
    +-------------+
    mysql> SHOW SESSION STATUS LIKE 'Handler%';
    +----------------------------+-------+
    | Variable_name              | Value |
    +----------------------------+-------+
    | Handler_external_lock      | 2     |
    | Handler_read_first         | 1     |
    | Handler_read_key           | 2     |
    | Handler_read_last          | 1     |
    | Handler_read_next          | 4175  | -- full index scan
    
    (etc)
    
    +----+-------------+-----------+-------+-----------------------+------------+---------+------+------+--------------------------------------------------+
    | id | select_type | table     | type  | possible_keys         | key        | key_len | ref  | rows | Extra                                            |
    +----+-------------+-----------+-------+-----------------------+------------+---------+------+------+--------------------------------------------------+
    |  1 | SIMPLE      | us_vch200 | range | state_city,city_state | city_state | 769     | NULL | 4176 | Using where; Using index for group-by (scanning) |
    +----+-------------+-----------+-------+-----------------------+------------+---------+------+------+--------------------------------------------------+
    

    「Extra」は、GROUP BYに取り組むことを決定したことを示しています INDEX(city, state)を使用します INDEX(state, city)であっても 理にかなっているかもしれません。

    HAVING、バージョン2

    INDEX(state, city)に切り替えます 収量:

    mysql> FLUSH STATUS;
    mysql> SELECT city
        ->     FROM us_vch200  IGNORE INDEX(city_state)
        ->     WHERE state IN ('IL', 'MO', 'PA')
        ->     GROUP BY city
        ->     HAVING count(DISTINCT state) >= 3;
    +-------------+
    | city        |
    +-------------+
    | Springfield |
    | Washington  |
    +-------------+
    mysql> SHOW SESSION STATUS LIKE 'Handler%';
    +----------------------------+-------+
    | Variable_name              | Value |
    +----------------------------+-------+
    | Handler_commit             | 1     |
    | Handler_external_lock      | 2     |
    | Handler_read_key           | 401   |
    | Handler_read_next          | 398   |
    | Handler_read_rnd           | 398   |
    (etc)
    
    +----+-------------+-----------+-------+-----------------------+------------+---------+------+------+------------------------------------------+
    | id | select_type | table     | type  | possible_keys         | key        | key_len | ref  | rows | Extra                                    |
    +----+-------------+-----------+-------+-----------------------+------------+---------+------+------+------------------------------------------+
    |  1 | SIMPLE      | us_vch200 | range | state_city,city_state | state_city | 2       | NULL |  397 | Using where; Using index; Using filesort |
    +----+-------------+-----------+-------+-----------------------+------------+---------+------+------+------------------------------------------+
    

    参加

    mysql> SELECT x.city
        -> FROM us_vch200 x
        -> JOIN us_vch200 y ON y.city= x.city AND y.state = 'MO'
        -> JOIN us_vch200 z ON z.city= x.city AND z.state = 'PA'
        -> WHERE                                  x.state = 'IL';
    +-------------+
    | city        |
    +-------------+
    | Springfield |
    | Washington  |
    +-------------+
    2 rows in set (0.00 sec)
    
    mysql> SHOW SESSION STATUS LIKE 'Handler%';
    +----------------------------+-------+
    | Variable_name              | Value |
    +----------------------------+-------+
    | Handler_commit             | 1     |
    | Handler_external_lock      | 6     |
    | Handler_read_key           | 86    |
    | Handler_read_next          | 87    |
    (etc)    
    +----+-------------+-------+------+-----------------------+------------+---------+--------------------+------+--------------------------+
    | id | select_type | table | type | possible_keys         | key        | key_len | ref                | rows | Extra                    |
    +----+-------------+-------+------+-----------------------+------------+---------+--------------------+------+--------------------------+
    |  1 | SIMPLE      | y     | ref  | state_city,city_state | state_city | 2       | const              |   81 | Using where; Using index |
    |  1 | SIMPLE      | z     | ref  | state_city,city_state | state_city | 769     | const,world.y.city |    1 | Using where; Using index |
    |  1 | SIMPLE      | x     | ref  | state_city,city_state | state_city | 769     | const,world.y.city |    1 | Using where; Using index |
    +----+-------------+-------+------+-----------------------+------------+---------+--------------------+------+--------------------------+
    

    INDEX(state, city)のみ が必要です。この定式化ではハンドラー番号が最小であるため、最速であると推測します。

    おそらく

    が原因で、オプティマイザがどのテーブルから開始するかを独自に決定したことに注目してください。
    +-------+----------+
    | state | COUNT(*) |
    +-------+----------+
    | IL    |      221 |
    | MO    |       81 |  -- smallest
    | PA    |       96 |
    +-------+----------+
    

    結論

    JOIN (不要なtなし 表)はおそらく最速です。さらに、この複合インデックスが必要です:INDEX(state, city)

    ユースケースに戻すには:

    city --> documentid
    state --> termid
    

    警告:YMMV。documentidとtermidの値の分布は、私が使用したテストケースとはかなり異なる可能性があるためです。




    1. 反復せずにカーソル内のmysqlレコード数?

    2. SQLiteテーブル制約が一意でONCONFLICTREPLACEの使用法

    3. 新しい行に対してのみ、デフォルトのNOW()でタイムスタンプ列を追加します

    4. 時系列データベースとは何ですか?