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

複数の行に対するSQLクエリ

    別のアプローチは-

    SELECT housing_id
    FROM mytable
    WHERE facility_id IN (4,7)
    GROUP BY housing_id
    HAVING COUNT(DISTINCT facility_id) = 2
    

    更新 --Josvicのコメントに触発されて、さらにテストを行うことにし、調査結果を含めることにしました。

    このクエリを使用する利点の1つは、より多くのfacility_idを含めるように簡単に変更できることです。 Facility_ids 1、3、4、および7を持つすべてのhousing_idsを検索する場合は、-

    SELECT housing_id
    FROM mytable
    WHERE facility_id IN (1,3,4,7)
    GROUP BY housing_id
    HAVING COUNT(DISTINCT facility_id) = 4
    

    これら3つのクエリすべてのパフォーマンスは、採用されているインデックス作成戦略によって大きく異なります。使用されているインデックスに関係なく、依存するサブクエリのバージョンから、テストデータセットで妥当なパフォーマンスを得ることができませんでした。

    Timが提供する自己結合ソリューションは、2つの列に個別の単一列インデックスを指定すると非常にうまく機能しますが、基準の数が増えるほどうまく機能しません。

    これが私のテストテーブルのいくつかの基本的な統計です-500k行-147963housing_idsとfacility_idの潜在的な値は1から9の間です。

    これらすべてのテストを実行するために使用されるインデックスは次のとおりです-

    SHOW INDEXES FROM mytable;
    +---------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
    | Table   | Non_unique | Key_name            | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type |
    +---------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
    | mytable |          0 | UQ_housing_facility |            1 | housing_id  | A         |      500537 |     NULL | NULL   |      | BTREE      |
    | mytable |          0 | UQ_housing_facility |            2 | facility_id | A         |      500537 |     NULL | NULL   |      | BTREE      |
    | mytable |          0 | UQ_facility_housing |            1 | facility_id | A         |          12 |     NULL | NULL   |      | BTREE      |
    | mytable |          0 | UQ_facility_housing |            2 | housing_id  | A         |      500537 |     NULL | NULL   |      | BTREE      |
    | mytable |          1 | IX_housing          |            1 | housing_id  | A         |      500537 |     NULL | NULL   |      | BTREE      |
    | mytable |          1 | IX_facility         |            1 | facility_id | A         |          12 |     NULL | NULL   |      | BTREE      |
    +---------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
    

    テストされる最初のクエリは、依存サブクエリです-

    SELECT SQL_NO_CACHE DISTINCT housing_id
    FROM mytable
    WHERE housing_id IN (SELECT housing_id FROM mytable WHERE facility_id=4)
    AND housing_id IN (SELECT housing_id FROM mytable WHERE facility_id=7);
    
    17321 rows in set (9.15 sec)
    
    +----+--------------------+---------+-----------------+----------------------------------------------------------------+---------------------+---------+------------+--------+---------------------------------------+
    | id | select_type        | table   | type            | possible_keys                                                  | key                 | key_len | ref        | rows   | Extra                                 |
    +----+--------------------+---------+-----------------+----------------------------------------------------------------+---------------------+---------+------------+--------+---------------------------------------+
    |  1 | PRIMARY            | mytable | range           | NULL                                                           | IX_housing          | 4       | NULL       | 500538 | Using where; Using index for group-by |
    |  3 | DEPENDENT SUBQUERY | mytable | unique_subquery | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | func,const |      1 | Using index; Using where              |
    |  2 | DEPENDENT SUBQUERY | mytable | unique_subquery | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | func,const |      1 | Using index; Using where              |
    +----+--------------------+---------+-----------------+----------------------------------------------------------------+---------------------+---------+------------+--------+---------------------------------------+
    
    SELECT SQL_NO_CACHE DISTINCT housing_id
    FROM mytable
    WHERE housing_id IN (SELECT housing_id FROM mytable WHERE facility_id=1)
    AND housing_id IN (SELECT housing_id FROM mytable WHERE facility_id=3)
    AND housing_id IN (SELECT housing_id FROM mytable WHERE facility_id=4)
    AND housing_id IN (SELECT housing_id FROM mytable WHERE facility_id=7);
    
    567 rows in set (9.30 sec)
    
    +----+--------------------+---------+-----------------+----------------------------------------------------------------+---------------------+---------+------------+--------+---------------------------------------+
    | id | select_type        | table   | type            | possible_keys                                                  | key                 | key_len | ref        | rows   | Extra                                 |
    +----+--------------------+---------+-----------------+----------------------------------------------------------------+---------------------+---------+------------+--------+---------------------------------------+
    |  1 | PRIMARY            | mytable | range           | NULL                                                           | IX_housing          | 4       | NULL       | 500538 | Using where; Using index for group-by |
    |  5 | DEPENDENT SUBQUERY | mytable | unique_subquery | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | func,const |      1 | Using index; Using where              |
    |  4 | DEPENDENT SUBQUERY | mytable | unique_subquery | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | func,const |      1 | Using index; Using where              |
    |  3 | DEPENDENT SUBQUERY | mytable | unique_subquery | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | func,const |      1 | Using index; Using where              |
    |  2 | DEPENDENT SUBQUERY | mytable | unique_subquery | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | func,const |      1 | Using index; Using where              |
    +----+--------------------+---------+-----------------+----------------------------------------------------------------+---------------------+---------+------------+--------+---------------------------------------+
    

    次は、GROUP BY ...HAVINGCOUNTを使用した私のバージョンです...

    SELECT SQL_NO_CACHE housing_id
    FROM mytable
    WHERE facility_id IN (4,7)
    GROUP BY housing_id
    HAVING COUNT(DISTINCT facility_id) = 2;
    
    17321 rows in set (0.79 sec)
    
    +----+-------------+---------+-------+---------------------------------+-------------+---------+------+--------+------------------------------------------+
    | id | select_type | table   | type  | possible_keys                   | key         | key_len | ref  | rows   | Extra                                    |
    +----+-------------+---------+-------+---------------------------------+-------------+---------+------+--------+------------------------------------------+
    |  1 | SIMPLE      | mytable | range | UQ_facility_housing,IX_facility | IX_facility | 4       | NULL | 198646 | Using where; Using index; Using filesort |
    +----+-------------+---------+-------+---------------------------------+-------------+---------+------+--------+------------------------------------------+
    
    SELECT SQL_NO_CACHE housing_id
    FROM mytable
    WHERE facility_id IN (1,3,4,7)
    GROUP BY housing_id
    HAVING COUNT(DISTINCT facility_id) = 4;
    
    567 rows in set (1.25 sec)
    
    +----+-------------+---------+-------+---------------------------------+-------------+---------+------+--------+------------------------------------------+
    | id | select_type | table   | type  | possible_keys                   | key         | key_len | ref  | rows   | Extra                                    |
    +----+-------------+---------+-------+---------------------------------+-------------+---------+------+--------+------------------------------------------+
    |  1 | SIMPLE      | mytable | range | UQ_facility_housing,IX_facility | IX_facility | 4       | NULL | 407160 | Using where; Using index; Using filesort |
    +----+-------------+---------+-------+---------------------------------+-------------+---------+------+--------+------------------------------------------+
    

    そして最後になりましたが、自己参加-

    SELECT SQL_NO_CACHE a.housing_id
    FROM mytable a
    INNER JOIN mytable b
        ON a.housing_id = b.housing_id
    WHERE a.facility_id = 4 AND b.facility_id = 7;
    
    17321 rows in set (1.37 sec)
    
    +----+-------------+-------+--------+----------------------------------------------------------------+---------------------+---------+-------------------------+-------+-------------+
    | id | select_type | table | type   | possible_keys                                                  | key                 | key_len | ref                     | rows  | Extra       |
    +----+-------------+-------+--------+----------------------------------------------------------------+---------------------+---------+-------------------------+-------+-------------+
    |  1 | SIMPLE      | b     | ref    | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | IX_facility         | 4       | const                   | 94598 | Using index |
    |  1 | SIMPLE      | a     | eq_ref | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | test.b.housing_id,const |     1 | Using index |
    +----+-------------+-------+--------+----------------------------------------------------------------+---------------------+---------+-------------------------+-------+-------------+
    
    SELECT SQL_NO_CACHE a.housing_id
    FROM mytable a
    INNER JOIN mytable b
        ON a.housing_id = b.housing_id
    INNER JOIN mytable c
        ON a.housing_id = c.housing_id
    INNER JOIN mytable d
        ON a.housing_id = d.housing_id
    WHERE a.facility_id = 1
    AND b.facility_id = 3
    AND c.facility_id = 4
    AND d.facility_id = 7;
    
    567 rows in set (1.64 sec)
    
    +----+-------------+-------+--------+----------------------------------------------------------------+---------------------+---------+-------------------------+-------+--------------------------+
    | id | select_type | table | type   | possible_keys                                                  | key                 | key_len | ref                     | rows  | Extra                    |
    +----+-------------+-------+--------+----------------------------------------------------------------+---------------------+---------+-------------------------+-------+--------------------------+
    |  1 | SIMPLE      | b     | ref    | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | IX_facility         | 4       | const                   | 93782 | Using index              |
    |  1 | SIMPLE      | d     | eq_ref | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | test.b.housing_id,const |     1 | Using index              |
    |  1 | SIMPLE      | c     | eq_ref | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | test.b.housing_id,const |     1 | Using index              |
    |  1 | SIMPLE      | a     | eq_ref | UQ_housing_facility,UQ_facility_housing,IX_housing,IX_facility | UQ_housing_facility | 8       | test.d.housing_id,const |     1 | Using where; Using index |
    +----+-------------+-------+--------+----------------------------------------------------------------+---------------------+---------+-------------------------+-------+--------------------------+
    


    1. 複合主キーを外部キーとして使用する

    2. Mysql:ドットの後に特定の数を超える小数点が含まれるすべての行を取得する方法

    3. MySQLの単一引用符、二重引用符、およびバッククォート

    4. MySQLの共通テーブル式