繁体   English   中英

如何使此查询更高效?

[英]how can I make this query more efficient?

编辑:这是原始查询的简化版本(在475K行的产品表上以3.6秒的时间运行)

SELECT p.*, shop FROM products p JOIN
users u ON p.date >= u.prior_login and u.user_id = 22 JOIN
shops s ON p.shop_id = s.shop_id
ORDER BY shop, date, product_id;

这是解释计划

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  u   const   PRIMARY,prior_login,user_id PRIMARY 4   const   1   Using temporary; Using filesort
1   SIMPLE  s   ALL PRIMARY NULL    NULL    NULL    90   
1   SIMPLE  p   ref shop_id,date,shop_id_2,shop_id_3    shop_id 4   bitt3n_minxa.s.shop_id  5338    Using where

瓶颈似乎是ORDER BY date,product_id 删除这两个顺序,查询将在0.06秒内运行。 (删除这两者之一(但不能全部删除)几乎没有任何效果,查询仍然需要3秒钟以上。)我在product表中同时具有product_id和date的索引。 我还添加了关于(产品,日期)的索引,但没有改善。

newtover提示问题在于, INNER JOIN users u1 ON products.date >= u1.prior_login要求阻止了在products.date上使用索引

已经向我建议了两种查询变体,它们在〜0.006秒(而不是原始的3.6秒)内执行(不是从该线程执行的)。

这使用了一个子查询,该子查询似乎强制了连接的顺序

SELECT p.*, shop 
  FROM 
  (
    SELECT p.*
    FROM products p 
    WHERE p.date >= (select prior_login FROM users where user_id = 22)
  ) as p
  JOIN shops s 
    ON p.shop_id = s.shop_id
  ORDER BY shop, date, product_id;

此代码使用WHERE子句执行相同的操作(尽管SQL_SMALL_RESULT的存在并不会更改执行时间,没有SQL_SMALL_RESULT的执行时间也会更改为0.006秒)

SELECT SQL_SMALL_RESULT p . * , shop
FROM products p
INNER JOIN shops s ON p.shop_id = s.shop_id
WHERE p.date >= ( 
SELECT prior_login
FROM users
WHERE user_id =22 ) 
ORDER BY shop, DATE, product_id;

我的理解是,由于在将产品表连接到shops表之前减少了产品表的相关行数,因此这些查询的工作速度更快。 我想知道这是否正确。

使用EXPLAIN语句查看执行计划。 您也可以尝试向products.dateu1.prior_login添加索引。

另外,请确保已定义外键并已对其进行索引。

祝好运。

我们确实需要一个解释计划...但是

要非常小心,从表中的id中选择* *(从another_table中选择id)这是一个臭名昭著的事情。 通常,这些可以替换为联接。 以下查询可能会运行,尽管我尚未对其进行测试。

SELECT shop,
       shops.shop_id AS shop_id,
       products.product_id AS product_id,
       brand,
       title,
       price,
       image AS image,
       image_width,
       image_height,
       0 AS sex,
       products.date AS date,
       fav1.favorited AS circle_favorited,
       fav2.favorited AS session_user_favorited,
       u2.username AS circle_username
  FROM products
       LEFT JOIN favorites fav2
          ON     fav2.product_id = products.product_id
             AND fav2.user_id = 22
             AND fav2.current = 1
       INNER JOIN shops
          ON shops.shop_id = products.shop_id
       INNER JOIN users u1
          ON products.date >= u1.prior_login AND u1.user_id = 22
       LEFT JOIN favorites fav1
          ON products.product_id = fav1.product_id
       LEFT JOIN friends f1
          ON f1.star_id = fav1.user_id
       LEFT JOIN users u2
          ON fav1.user_id = u2.user_id
 WHERE f1.fan_id = 22 OR fav1.user_id = 22
ORDER BY shop,
         DATE,
         product_id,
         circle_favorited

由于排序很慢,查询很慢这一事实非常明显,因为在这种情况下很难找到要应用ORDER BY的索引。 主要问题是products.date >=比较,它使用ORDER BY的任何索引时都会中断。 而且由于要输出大量数据,MySQL开始使用临时表进行排序。

我要做的是尝试按已经具有所需顺序的索引顺序强制MySQL输出数据,并删除ORDER BY子句。

我不是要测试的计算机,但是我将如何做:

  • 我会做所有内部联接
  • 然后我将LEFT JOIN到一个子查询,该子查询对由product_id,circle_favourited(将提供最后的排序条件)排序的收藏夹进行所有计算。

因此,问题是如何使数据在商店,日期,product_id上排序

我稍后再写=)

UPD1:

您可能应该阅读有关btree索引如何在MySQL中工作的内容。 mysqlperformanceblog.com上有一篇很好的文章(我目前在手机上撰写,没有链接可用)。 简而言之,您似乎在谈论单列索引,该索引基于在单列中排序的值来排列指向行的指针。 复合索引基于多个列存储订单。 在从索引所指向的行中检索数据之前,大多数索引通常用于对其明确定义的范围进行操作,以获取大多数信息。 索引通常不知道同一张表上的其他索引,因此它们很少合并。 当索引中没有更多信息时,MySQL开始直接对数据进行操作。

也就是说,日期索引不能使用product_id上的索引,但是日期日期后(针对特定日期匹配的产品ID排序),(日期,product_id)上的索引可以获取有关product_id的更多信息。

但是,日期范围条件(> =)打破了这一点。 那就是我在说的。

UPD2:

据我了解,这个问题可以减少到(大部分时间都花在此上):

SELECT p.*, shop
FROM products p
JOIN users u ON p.`date` >= u.prior_login and u.user_id = 22
JOIN shops s ON p.shop_id = s.shop_id
ORDER BY shop, `date`, product_id;

现在在用户上添加索引(user_id,previous_login),在产品上添加索引(date),然后尝试以下查询:

SELECT STRAIGHT_JOIN p.*, shop
FROM (
  SELECT product_id, shop
  FROM users u
  JOIN products p
    user_id = 22 AND p.`date` >= prior_login
  JOIN shops s
    ON p.shop_id = s.shop_id
  ORDER BY shop, p.`date`, product_id
) as s
JOIN products p USING (product_id);

如果我是正确的,查询应该返回相同的结果,但速度更快。 如果可以,则将EXPLAIN的结果发布给查询。

暂无
暂无

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

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