简体   繁体   English

mysql查询优化-join和orderby

[英]mysql query optimization - join and orderby

I need a little help by one mysql query optimization. 我需要一个mysql查询优化的帮助。 It is a simple query but anything is not right and I can't found it :-( 这是一个简单的查询,但是任何不正确的操作我都找不到:-(

I have 2 tables: products (> 40000 Rows) and product_tags (> 5 mil) 我有2个表格:产品(> 40000行)和product_tags(> 500万)

There is a relation betweet the tables 1 -> N . 表1-> N之间有一个关系。 Every prdoduct can have many tags in the table product tags. 每个产品在表产品标签中可以有许多标签。

I have this simple Query: 我有这个简单的查询:

EXPLAIN SELECT t.product_id, kwt.tag_id
FROM products AS t, product_tags AS kwt
WHERE 1
AND t.product_id = kwt.product_id
AND kwt.tag_id =11
ORDER BY t.order_date 

wchich returns 55 results. wchich返回55个结果。

First Situation: if I have this table structure of the tables: 第一种情况:如果我具有以下表格的表格结构:

CREATE TABLE IF NOT EXISTS `products` (
  `product_id` int(10) unsigned NOT NULL auto_increment,
  `product_source_id` smallint(5) unsigned NOT NULL,
  `order_date` int(10) unsigned NOT NULL,
  PRIMARY KEY  (`product_id`),
  KEY `order_date` (`order_date`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;


CREATE TABLE IF NOT EXISTS `product_tags` (
  `product_tag_id` int(10) unsigned NOT NULL auto_increment,
  `tag_id` int(10) unsigned NOT NULL,
  `product_id` int(11) NOT NULL,
  PRIMARY KEY  (`product_tag_id`),
  KEY `product_id` (`product_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8  ;

Then the Explain of the query is this: 那么查询的解释是这样的:

+----+-------------+-------+-------+---------------+------------+---------+---------------------------+-------+-------------+
| id | select_type | table | type  | possible_keys | key        | key_len | ref                       | rows  | Extra       |
+----+-------------+-------+-------+---------------+------------+---------+---------------------------+-------+-------------+
|  1 | SIMPLE      | t     | index | PRIMARY       | order_date | 4       | NULL                      | 45392 | Using index | 
|  1 | SIMPLE      | kwt   | ref   | product_id    | product_id | 4       | t.product_id          |     3 | Using where | 
+----+-------------+-------+-------+---------------+------------+---------+---------------------------+-------+-------------+

It is getting all the rows from table products, but there is nothing with temporary table. 它从表产品获取所有行,但是临时表没有任何内容。

Second Situation: If I add an index for the field "tag_id" in product_tags, then the picture is different: 第二种情况:如果我在product_tags中为“ tag_id”字段添加索引,则图片将有所不同:

+----+-------------+-------+--------+-------------------+---------+---------+-----------------------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys     | key     | key_len | ref                         | rows | Extra                           |
+----+-------------+-------+--------+-------------------+---------+---------+-----------------------------+------+---------------------------------+
|  1 | SIMPLE      | kwt   | ref    | product_id,tag_id | tag_id  | 4       | const                       |   55 | Using temporary; Using filesort | 
|  1 | SIMPLE      | t     | eq_ref | PRIMARY           | PRIMARY | 4       | kwt.product_id              |    1 | Using where                     | 
+----+-------------+-------+--------+-------------------+---------+---------+-----------------------------+------+---------------------------------+

Now it selects only 55 rows, what is right, but the query is havy :( 现在它只选择55行,没错,但是查询很复杂:(

Where is my mistake here ? 我的错在哪里?

Thanks Nik 谢谢尼克

this is what i would do: 这就是我会做的:

Read these resources 阅读这些资源

Redesign your system to take advantage of a clustered primary key 重新设计系统以利用集群主键

Simplified schema: 简化架构:

drop table if exists products;
create table products
(
prod_id int unsigned not null auto_increment primary key,
name varchar(255) not null unique
)
engine = innodb; 

drop table if exists tags;
create table tags
(
tag_id mediumint unsigned not null auto_increment primary key,
name varchar(255) not null unique
)
engine = innodb; 

drop table if exists product_tags;
create table product_tags
(
tag_id mediumint unsigned not null,
prod_id int unsigned not null,
created_date date not null,
primary key (tag_id, prod_id), -- note the clustered composite index and the order !!
key (prod_id)
)
engine = innodb;

Test the schema 测试架构

select
 pt.tag_id,
 pt.prod_id
from
 product_tags pt
inner join products p on pt.prod_id = p.prod_id
where
 pt.tag_id = 11
order by
 pt.created_date
limit 10;

I may even change the product_tags PK to primary key (tag_id, prod_id, created_date) but it all depends on the typical queries you run. 我什至可以将product_tags PK更改为主键(tag_id,prod_id,created_date),但这全都取决于您运行的典型查询。 You could ofc, just create a non clustered secondary index on created date if you think that's gonna boost performance. 如果您认为可以提高性能,则可以在创建日期创建一个非聚集二级索引。

Hope this helps :) 希望这可以帮助 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM