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

多対多のクエリで一時的なものを使用しないようにするにはどうすればよいですか?

    これは、innodbのクラスター化された主キーインデックスを利用する、同様のパフォーマンス関連の質問に対して行った簡略化された例です(明らかに、innodbでのみ使用可能です!!)

    次の3つのテーブルがあります:category、product、product_category:

    drop table if exists product;
    create table product
    (
    prod_id int unsigned not null auto_increment primary key,
    name varchar(255) not null unique
    )
    engine = innodb; 
    
    drop table if exists category;
    create table category
    (
    cat_id mediumint unsigned not null auto_increment primary key,
    name varchar(255) not null unique
    )
    engine = innodb; 
    
    drop table if exists product_category;
    create table product_category
    (
    cat_id mediumint unsigned not null,
    prod_id int unsigned not null,
    primary key (cat_id, prod_id) -- **note the clustered composite index** !!
    )
    engine = innodb;
    

    最も重要なのは、product_catgeoryクラスター化複合主キーの順序です。 このシナリオの一般的なクエリは、常にcat_id =xまたはcat_idin(x、y、z ...)によって導かれます。

    500K カテゴリ、100万 製品と1億2500万 製品カテゴリ。

    select count(*) from category;
    +----------+
    | count(*) |
    +----------+
    |   500000 |
    +----------+
    
    select count(*) from product;
    +----------+
    | count(*) |
    +----------+
    |  1000000 |
    +----------+
    
    select count(*) from product_category;
    +-----------+
    | count(*)  |
    +-----------+
    | 125611877 |
    +-----------+
    

    それでは、このスキーマが自分のスキーマと同様のクエリに対してどのように実行されるかを見てみましょう。すべてのクエリは、空のバッファとクエリキャッシュなしで(mysqlの再起動後に)コールドで実行されます。

    select
     p.*
    from
     product p
    inner join product_category pc on 
        pc.cat_id = 4104 and pc.prod_id = p.prod_id
    order by
     p.prod_id desc -- sry dont a date field in this sample table - wont make any difference though
    limit 20;
    
    +---------+----------------+
    | prod_id | name           |
    +---------+----------------+
    |  993561 | Product 993561 |
    |  991215 | Product 991215 |
    |  989222 | Product 989222 |
    |  986589 | Product 986589 |
    |  983593 | Product 983593 |
    |  982507 | Product 982507 |
    |  981505 | Product 981505 |
    |  981320 | Product 981320 |
    |  978576 | Product 978576 |
    |  973428 | Product 973428 |
    |  959384 | Product 959384 |
    |  954829 | Product 954829 |
    |  953369 | Product 953369 |
    |  951891 | Product 951891 |
    |  949413 | Product 949413 |
    |  947855 | Product 947855 |
    |  947080 | Product 947080 |
    |  945115 | Product 945115 |
    |  943833 | Product 943833 |
    |  942309 | Product 942309 |
    +---------+----------------+
    20 rows in set (0.70 sec) 
    
    explain
    select
     p.*
    from
     product p
    inner join product_category pc on 
        pc.cat_id = 4104 and pc.prod_id = p.prod_id
    order by
     p.prod_id desc -- sry dont a date field in this sample table - wont make any diference though
    limit 20;
    
    +----+-------------+-------+--------+---------------+---------+---------+------------------+------+----------------------------------------------+
    | id | select_type | table | type   | possible_keys | key     | key_len | ref           | rows | Extra                                        |
    +----+-------------+-------+--------+---------------+---------+---------+------------------+------+----------------------------------------------+
    |  1 | SIMPLE      | pc    | ref    | PRIMARY       | PRIMARY | 3       | const           |  499 | Using index; Using temporary; Using filesort |
    |  1 | SIMPLE      | p     | eq_ref | PRIMARY       | PRIMARY | 4       | vl_db.pc.prod_id |    1 |                                              |
    +----+-------------+-------+--------+---------------+---------+---------+------------------+------+----------------------------------------------+
    2 rows in set (0.00 sec)
    

    つまり、0.70秒の寒さです-痛いです。

    これがお役に立てば幸いです:)

    編集

    上記の私のコメントへの返信を読んだだけで、2つの選択肢のうちの1つがあるようです。

    create table articles_to_categories
    (
    article_id int unsigned not null,
    category_id mediumint unsigned not null,
    primary key(article_id, category_id), -- good for queries that lead with article_id = x
    key (category_id)
    )
    engine=innodb;
    

    または。

    create table categories_to_articles
    (
    article_id int unsigned not null,
    category_id mediumint unsigned not null,
    primary key(category_id, article_id), -- good for queries that lead with category_id = x
    key (article_id)
    )
    engine=innodb;
    

    あなたの典型的なに依存します クラスタ化されたPKをどのように定義するかについてのクエリ。



    1. 追加された複数のエンティティは、データベースシードに同じ主キーを持っている可能性があります

    2. SQLカウント-機能しない

    3. PostgreSQL、既存のテーブルを再構成し、主キーをtype=serialに変更します

    4. データベースからレコードをフェッチする際の動的行スパン