加快php / mysql查询/正确使用连接?

时间:2017-03-25 14:11:15

标签: php mysql codeigniter join query-optimization

我遇到一些问题,一些mysql查询需要大约50秒执行一些时间,但有时候大约1秒钟。查询做了我需要做的事情,但显然太慢了。

以下是使用的三个表并显示了一些列:

产品表(14315行)

id    | title  | image | price | rrp   | upsell
20381 | test   | test  | 24.00 | 30.00 | 1

product_to_category表(26283行)

ptc_id | product_id | category_id
33797  | 20381      | 29

category_description表(29行)

category_id | name     | url_slug
29          | Kitchens | kitchen-products

seo_slugs表(14898行)

seo_slug_id | route         | seo_slug
26987       | product=20381 | test-product-kitchen-area-2000-500

以下是我正在使用的当前codeigniter函数。

public function getUpsells() {
$this->db->select('products.id, products.title, products.image, products.category, products.price, products.rrp', FALSE);
$this->db->from('product_to_category');
$this->db->join('products', 'products.id = product_to_category.product_id');
$this->db->join('category_description', 'category_description.category_id = product_to_category.category_id');
$this->db->join('seo_slugs', 'seo_slugs.route = concat(\'product=\', product_to_category.product_id)');
$this->db->where('products.upsell',1);
$this->db->where('products.status',1);
$this->db->group_by('product_to_category.product_id');
$query = $this->db->get();
return $query->result();

} 我希望有人可以指出我正确的方向,并告诉我哪里出错了。说实话,我第一次在查询中使用了连接,虽然它似乎有用,但是在第一次加载页面时通常很慢,如果刷新等,它似乎加载相当快。

以下是它运行的查询:

SELECT products.id, products.title, products.image, products.category, products.price, products.rrp
FROM `product_to_category`
JOIN `products` ON `products`.`id` = `product_to_category`.`product_id`
JOIN `category_description` ON `category_description`.`category_id` = `product_to_category`.`category_id`
JOIN `seo_slugs` ON `seo_slugs`.`route` = concat('product=', product_to_category.product_id)
WHERE `products`.`upsell` = 1
AND `products`.`status` = 1
GROUP BY `product_to_category`.`product_id` 

分析结果:

Starting    18 µs
Waiting For Query Cache Lock    5 µs
Checking Query Cache For Query  48 µs
Checking Permissions    5 µs
Checking Permissions    4 µs
Checking Permissions    4 µs
Checking Permissions    5 µs
Opening Tables  20 µs
System Lock 9 µs
Waiting For Query Cache Lock    15 µs
Init    25 µs
Optimizing  13 µs
Statistics  23 µs
Preparing   19 µs
Creating Tmp Table  21 µs
Executing   5 µs
Copying To Tmp Table    51.8 s
Sorting Result  26 µs
Sending Data    24 µs
End 9 µs
Removing Tmp Table  33 µs
End 7 µs
Query End   7 µs
Closing Tables  14 µs
Freeing Items   12 µs
Waiting For Query Cache Lock    6 µs
Freeing Items   11 µs
Waiting For Query Cache Lock    7 µs
Freeing Items   7 µs
Storing Result In Query Cache   162 µs
Logging Slow Query  6 µs
Logging Slow Query  38 µs
Cleaning Up 7 µs

EXPLAIN结果:

+----+-------------+----------------------+--------+---------------+---------+---------+-----------------------------------------------------+-------+---------------------------------+
| id | select_type |        table         |  type  | possible_keys |   key   | key_len |                         ref                         | rows  |              Extra              |
+----+-------------+----------------------+--------+---------------+---------+---------+-----------------------------------------------------+-------+---------------------------------+
|  1 | SIMPLE      | seo_slugs            | ALL    | NULL          | NULL    | NULL    | NULL                                                | 14958 | Using temporary; Using filesort |
|  1 | SIMPLE      | product_to_category  | ALL    | category_id   | NULL    | NULL    | NULL                                                | 26343 | Using where; Using join buffer  |
|  1 | SIMPLE      | category_description | eq_ref | PRIMARY       | PRIMARY | 4       | wilsonar_hcsupplies.product_to_category.category_id |     1 | Using index                     |
|  1 | SIMPLE      | products             | eq_ref | PRIMARY,id    | PRIMARY | 4       | wilsonar_hcsupplies.product_to_category.product_id  |     1 | Using where                     |
+----+-------------+----------------------+--------+---------------+---------+---------+-----------------------------------------------------+-------+---------------------------------+

2 个答案:

答案 0 :(得分:0)

EXPLAIN告诉我们product_to_category有一个MySQL考虑使用的索引,因为possible_keys是“category_id”。但是,由于某种原因,它没有被使用。

“rows”是26343,“key”是NULL,这意味着MySQL必须扫描所有 每个产品的product_to_category中有26343行,即使使用连接缓冲区优化也会非常可怕。

product_to_category Table (26283 rows)
ptc_id | product_id | category_id
33797  | 20381      | 29

ptc_id没用,因为此表的主键应该是(category_id,product_id),并且(product_id,category_id)上添加了UNIQUE索引以优化搜索。这让我怀疑数据库结构,因此我打赌设计者使用了错误的类型(即除了INT之外的任何东西)用于其中一个表中的一列。因此,请检查您的列类型是否为tinyint,smallint,bigint,unsigned,等等......

其他原因是名为category_id的索引实际上并未对列category_id编制索引。你永远都不会知道。请检查。

现在,查询还有另一个问题,即GROUP BY使整个查询无效。我想知道这个查询应该做什么......

答案 1 :(得分:0)

(我还没有看到有用的“个人资料”。)

即使没有看到* { margin: 0; padding: 0; -ms-box-sizing: border-box; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } html, body { height: 100%; color: #0068ac; } body { text-align: center; background: #689976; } .col-6-{width: 48%;} body { background: gray; } #base { display: inline-block; padding-top: 5%; height: 90%; /* width: 90%; */ } #form { height: 98%; background: #E6F0F7; border-radius: 0 0 5px 5px; } #banner a { text-decoration: none; outline: none; display: block; float: left; font-size: 12px; line-height: 36px; position: relative; padding: 0 10px 0 60px; color: #ffe143; background: #32a252; height: 2em; } .col-6- { display: inline-block; } #form div div { text-align: left; vertical-align: top; padding: 1%; } #form div p { word-break: break-all; } 的表结构,我怀疑它是缺陷部分。

  • 摆脱product_to_category
  • 更改为ptc_id
  • 还有PRIMARY KEY(product_id, category_id)

Further discussion最优的多个:许多映射表。

此外,还有INDEX(category_id, product_id)。可以使用或不使用此复合索引,具体取决于这些列的基数。如果有用,那将是非常有益的。如果没有,则需要进行表扫描。

摆脱最后两个join()s - 你不使用那些表。 MySQL正在加入以确保它们存在,但浪费时间这样做。

一旦摆脱了两个不必要的表,就可以摆脱INDEX(upsell, status)

但是,为什么要轻触GROUP BY?摆脱它,摆脱categories

所以这就是你需要的是上面的索引,再加上

products_to_categories

但是,等等!这不起作用,因为没有SELECT id, title, image, category, price, rrp FROM `products` WHERE `upsell` = 1 AND `status` = 1

为什么有时快?您已打开“查询缓存”。当任何更改任何相关表之前第二次运行相同的查询时,它将从QC中获取,通常在一毫秒左右。