如何优化这个subqueried和Joined MySQL Query?

时间:2009-06-28 02:11:52

标签: mysql query-optimization

我在mysql上非常环保,我需要一些清理查询的技巧。它通过一个站点用于多种变体。它有一些subquerys派生表和乐趣继续。继承人查询:

# Query_time: 2  Lock_time: 0  Rows_sent: 0  Rows_examined: 0
SELECT *
  FROM (
  SELECT products . *, categories.category_name AS category, (
  SELECT COUNT( * )
  FROM distros
  WHERE distros.product_id = products.product_id) AS distro_count,
  (SELECT COUNT(*) FROM downloads WHERE downloads.product_id = products.product_id AND WEEK(downloads.date) = WEEK(curdate())) AS true_downloads,
  (SELECT COUNT(*) FROM views WHERE views.product_id = products.product_id AND WEEK(views.date) = WEEK(curdate())) AS true_views
  FROM products
  INNER JOIN categories ON products.category_id = categories.category_id ORDER BY created_date DESC, true_views DESC ) AS count_table
  WHERE count_table.distro_count > 0
  AND count_table.status = 'published'
  AND count_table.active = 1 LIMIT 0, 8

下面是解释:

+----+--------------------+------------+-------+---------------+-------------+---------+------------------------------------+------+----------------------------------------------+
| id | select_type        | table      | type  | possible_keys | key         | key_len | ref                                | rows | Extra                                        |
+----+--------------------+------------+-------+---------------+-------------+---------+------------------------------------+------+----------------------------------------------+
|  1 | PRIMARY            | <derived2> | ALL   | NULL          | NULL        | NULL    | NULL                               |  232 | Using where                                  |
|  2 | DERIVED            | categories | index | PRIMARY       | idx_name    | 47      | NULL                               |   13 | Using index; Using temporary; Using filesort |
|  2 | DERIVED            | products   | ref   | category_id   | category_id | 4       | digizald_db.categories.category_id |    9 |                                              |
|  5 | DEPENDENT SUBQUERY | views      | ref   | product_id    | product_id  | 4       | digizald_db.products.product_id    |   46 | Using where                                  |
|  4 | DEPENDENT SUBQUERY | downloads  | ref   | product_id    | product_id  | 4       | digizald_db.products.product_id    |   14 | Using where                                  |
|  3 | DEPENDENT SUBQUERY | distros    | ref   | product_id    | product_id  | 4       | digizald_db.products.product_id    |    1 | Using index                                  |
+----+--------------------+------------+-------+---------------+-------------+---------+------------------------------------+------+----------------------------------------------+
6 rows in set (0.04 sec)

表格:

mysql> describe products;
+---------------+--------------------------------------------------+------+-----+-------------------+----------------+
| Field         | Type                                             | Null | Key | Default           | Extra          |
+---------------+--------------------------------------------------+------+-----+-------------------+----------------+
| product_id    | int(10) unsigned                                 | NO   | PRI | NULL              | auto_increment |
| product_key   | char(32)                                         | NO   |     | NULL              |                |
| title         | varchar(150)                                     | NO   |     | NULL              |                |
| company       | varchar(150)                                     | NO   |     | NULL              |                |
| user_id       | int(10) unsigned                                 | NO   | MUL | NULL              |                |
| description   | text                                             | NO   |     | NULL              |                |
| video_code    | text                                             | NO   |     | NULL              |                |
| category_id   | int(10) unsigned                                 | NO   | MUL | NULL              |                |
| price         | decimal(10,2)                                    | NO   |     | NULL              |                |
| quantity      | int(10) unsigned                                 | NO   |     | NULL              |                |
| downloads     | int(10) unsigned                                 | NO   |     | NULL              |                |
| views         | int(10) unsigned                                 | NO   |     | NULL              |                |
| status        | enum('pending','published','rejected','removed') | NO   |     | NULL              |                |
| active        | tinyint(1)                                       | NO   |     | NULL              |                |
| deleted       | tinyint(1)                                       | NO   |     | NULL              |                |
| created_date  | datetime                                         | NO   |     | NULL              |                |
| modified_date | timestamp                                        | NO   |     | CURRENT_TIMESTAMP |                |
| scrape_source | varchar(215)                                     | YES  |     | NULL              |                |
+---------------+--------------------------------------------------+------+-----+-------------------+----------------+
18 rows in set (0.00 sec)

mysql> describe categories
    -> ;
+------------------+------------------+------+-----+---------+----------------+
| Field            | Type             | Null | Key | Default | Extra          |
+------------------+------------------+------+-----+---------+----------------+
| category_id      | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| category_name    | varchar(45)      | NO   | MUL | NULL    |                |
| parent_id        | int(10) unsigned | YES  | MUL | NULL    |                |
| category_type_id | int(10) unsigned | NO   |     | NULL    |                |
+------------------+------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> describe compatibilities
    -> ;
+------------------+------------------+------+-----+---------+----------------+
| Field            | Type             | Null | Key | Default | Extra          |
+------------------+------------------+------+-----+---------+----------------+
| compatibility_id | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name             | varchar(45)      | NO   |     | NULL    |                |
| code_name        | varchar(45)      | NO   |     | NULL    |                |
| description      | varchar(128)     | NO   |     | NULL    |                |
| position         | int(10) unsigned | NO   |     | NULL    |                |
+------------------+------------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)

mysql> describe distros
    -> ;
+------------------+--------------------------------------------------+------+-----+---------+----------------+
| Field            | Type                                             | Null | Key | Default | Extra          |
+------------------+--------------------------------------------------+------+-----+---------+----------------+
| id               | int(10) unsigned                                 | NO   | PRI | NULL    | auto_increment |
| product_id       | int(10) unsigned                                 | NO   | MUL | NULL    |                |
| compatibility_id | int(10) unsigned                                 | NO   | MUL | NULL    |                |
| user_id          | int(10) unsigned                                 | NO   |     | NULL    |                |
| status           | enum('pending','published','rejected','removed') | NO   |     | NULL    |                |
| distro_type      | enum('file','url')                               | NO   |     | NULL    |                |
| version          | varchar(150)                                     | NO   |     | NULL    |                |
| filename         | varchar(50)                                      | YES  |     | NULL    |                |
| url              | varchar(250)                                     | YES  |     | NULL    |                |
| virus            | enum('READY','PASS','FAIL')                      | YES  |     | NULL    |                |
| downloads        | int(10) unsigned                                 | NO   |     | 0       |                |
+------------------+--------------------------------------------------+------+-----+---------+----------------+
11 rows in set (0.01 sec)

mysql> describe downloads;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| product_id | int(10) unsigned | NO   | MUL | NULL    |                |
| distro_id  | int(10) unsigned | NO   | MUL | NULL    |                |
| user_id    | int(10) unsigned | NO   | MUL | NULL    |                |
| ip_address | varchar(15)      | NO   |     | NULL    |                |
| date       | datetime         | NO   |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)

mysql> describe views
    -> ;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| product_id | int(10) unsigned | NO   | MUL | NULL    |                |
| user_id    | int(10) unsigned | NO   | MUL | NULL    |                |
| ip_address | varchar(15)      | NO   |     | NULL    |                |
| date       | datetime         | NO   |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

3 个答案:

答案 0 :(得分:0)

有一件事我注意到这是一个很好的提示(可能是由新的优化器过时),因为一般的性能提升是在需要总计时使用COUNT(1)。 COUNT(*)必须处理列,而COUNT(1)只需要考虑行。

如果这不再是真的,请有人在这里发表评论,我会删除帖子。

另一个提示是永远不要使用SELECT *。通常,您应该始终枚举您选择的列,以便在表更改时隔离代码。

您真正想要做的一件事是将子查询移出SELECT块。联接通常比这些嵌套查询快得多。但请记住,优化器会为我们修复查询做大量的工作。如果优化器已经为我们做了,那么正确编写它可能不会显示出明显的改进!

这是您选择的子查询中的link

答案 1 :(得分:0)

首先,尝试对查询的格式设置和缩进做一些事情。 像这样,很难确切地看到发生了什么。

此页面可以合理地修复格式:http://www.dpriver.com/pp/sqlformat.htm

无论如何,看起来查询基本上试图显示几个表中的项目数。

而不是这样做:

select
  (select count(*) from myothertable1 where myothertableid=myothertable.id),
  (select count(*) from myothertable2 where myothertableid=myothertable.id),
  (select count(*) from myothertable3 where myothertableid=myothertable.id)
from 
  myothertable

你应该这样做:

select
  count(myothertable1.id),
  count(myothertable2.id),
  count(myothertable3.id)
from 
  mytable,
  myothertable1,
  myothertable2,
  myothertable3
where 
  myothertableid1=mytable.id and
  myothertableid2=mytable.id and
  myothertableid3=mytable.id

答案 2 :(得分:0)

只是为了表明我在Wouter van Nifterick´s anwswer的评论中的含义。 IMO,它应该是:

select
  count(myothertable1.id),
  count(myothertable2.id),
  count(myothertable3.id)
from mytable
left outer join myothertable1 on (myothertableid1=mytable.id)
left outer join myothertable2 on (myothertableid2=mytable.id)
left outer join myothertable3 on (myothertableid3=mytable.id)
where mytable.field = 'value'