sql >> Database >  >> RDS >> Mysql

Hoe voorkom je het gebruik van tijdelijk in veel-op-veel-query's?

Hier is een vereenvoudigd voorbeeld dat ik enige tijd geleden heb gemaakt voor een vergelijkbare prestatiegerelateerde vraag die gebruikmaakt van innodb geclusterde primaire sleutelindexen (uiteraard alleen beschikbaar met innodb !!)

Je hebt 3 tabellen:categorie, product en product_category als volgt:

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;

Het belangrijkste is de volgorde van de product_catgeory geclusterde samengestelde primaire sleutel als typische zoekopdrachten voor dit scenario altijd geleid door cat_id =x of cat_id in (x,y,z...).

We hebben 500K categorieën, 1 miljoen producten en 125 miljoen productcategorieën.

select count(*) from category;
+----------+
| count(*) |
+----------+
|   500000 |
+----------+

select count(*) from product;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+

select count(*) from product_category;
+-----------+
| count(*)  |
+-----------+
| 125611877 |
+-----------+

Laten we dus eens kijken hoe dit schema presteert voor een query die vergelijkbaar is met de uwe. Alle query's worden koud uitgevoerd (na herstart van mysql) met lege buffers en geen cache voor query's.

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)

Dus dat is 0,70 seconden koud - au.

Ik hoop dat dit helpt :)

BEWERKEN

Als ik net je antwoord op mijn opmerking hierboven heb gelezen, lijkt het erop dat je een van de twee keuzes moet maken:

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;

of.

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;

hangt af van uw typische vragen over hoe u uw geclusterde PK definieert.



  1. PostgreSQL via SSH-tunnel

  2. Hoe kunnen we ISNULL gebruiken voor alle kolomnamen in SQL Server 2008?

  3. Moet ik PDO PARAM_LOB of PARAM_STR gebruiken voor het MySQL TEXT-type?

  4. MySQL:is het mogelijk om meerdere rijen te group_concat?