优化mysql多个左连接

时间:2014-06-13 10:02:26

标签: mysql sql query-optimization

我有这样的查询:

SELECT
  SUM(c.cantitate) AS num,
  p.id             AS pid,
  p.titlu          AS titlu,
  p.alias          AS alias,
  p.gramaj         AS gramaj,
  p.prettotal      AS prettotal,
  p.pretunitar     AS pretunitar,
  p.pretredus      AS pretredus,
  p.stoc           AS stoc,
  p.cant_variabila AS cant_variabila,
  p.nou            AS nou,
  p.congelat       AS congelat,
  p.cod            AS cod,
  p.poza           AS poza,
  cc.seo           AS seo
FROM produse p
  LEFT JOIN (SELECT  produs, cantitate, COS FROM comenzi) c ON p.id = c.produs
  LEFT JOIN (SELECT STATUS, id FROM cosuri) cs ON c.cos = cs.id
  LEFT JOIN (SELECT id, seo FROM categorii) cc ON p.categorie = cc.id
WHERE cs.status = 'closed' AND p.vizibil = '1'
GROUP BY pid
ORDER BY num DESC
LIMIT 0, 14

查询正常,但1个查询的持续时间:2.922秒。 如何改进查询?

密钥如下:

comenzi:cos,produs as unique key

cosuri:id为唯一键

产品:titlu,类别,别名为关键

4 个答案:

答案 0 :(得分:4)

由于您有很多sub-queries,所以花费在完整数据读取上的时间。如果您直接在桌面上应用联接而不是sub query,则会提高效果。

删除所有子查询后尝试一下。像:

SELECT
  SUM(c.cantitate) AS num,
  p.id             AS pid,
  p.titlu          AS titlu,
  p.alias          AS alias,
  p.gramaj         AS gramaj,
  p.prettotal      AS prettotal,
  p.pretunitar     AS pretunitar,
  p.pretredus      AS pretredus,
  p.stoc           AS stoc,
  p.cant_variabila AS cant_variabila,
  p.nou            AS nou,
  p.congelat       AS congelat,
  p.cod            AS cod,
  p.poza           AS poza,
  cc.seo           AS seo
FROM produse p
  LEFT JOIN comenzi c
    ON p.id = c.produs
  LEFT JOIN cosuri cs
    ON c.cos = cs.id
  LEFT JOIN categorii cc
    ON p.categorie = cc.id
WHERE cs.status = 'closed'
    AND p.vizibil = '1'
GROUP BY pid
ORDER BY num DESC
LIMIT 0, 14

你也应该有以下索引:

+---------+------------+
|  TABLE  |   COLUMN   |
+---------+------------+
| produse | categorie  |
| produse | vizibil    |
| comenzi | produs     |
| comenzi | cos        |
| cosuri  | status     |
+---------+------------+

假设所有表中的id列表都是PK,否则这些列也需要index

答案 1 :(得分:0)

你可以这样做:花费更少的时间

SELECT
  SUM(c.cantitate) AS num,
  p.id             AS pid,
  p.titlu          AS titlu,
  p.alias          AS alias,
  p.gramaj         AS gramaj,
  p.prettotal      AS prettotal,
  p.pretunitar     AS pretunitar,
  p.pretredus      AS pretredus,
  p.stoc           AS stoc,
  p.cant_variabila AS cant_variabila,
  p.nou            AS nou,
  p.congelat       AS congelat,
  p.cod            AS cod,
  p.poza           AS poza,
  cc.seo           AS seo
FROM produse p
  LEFT JOIN comenzi c ON p.id = c.produs
  LEFT JOIN cosuri cs ON c.cos = cs.id
  LEFT JOIN categorii cc ON p.categorie = cc.id
WHERE cs.status = 'closed' AND p.vizibil = '1'
GROUP BY pid
ORDER BY num DESC
LIMIT 0, 14

答案 2 :(得分:0)

会很快

SELECT
  SUM(c.cantitate) AS num,
  p.id             AS pid,
  p.titlu          AS titlu,
  p.alias          AS alias,
  p.gramaj         AS gramaj,
  p.prettotal      AS prettotal,
  p.pretunitar     AS pretunitar,
  p.pretredus      AS pretredus,
  p.stoc           AS stoc,
  p.cant_variabila AS cant_variabila,
  p.nou            AS nou,
  p.congelat       AS congelat,
  p.cod            AS cod,
  p.poza           AS poza,
  cc.seo           AS seo
FROM produse p
  LEFT JOIN comenzi c ON p.id = c.produs
  LEFT JOIN cosuri cs ON c.cos = cs.id
  LEFT JOIN categorii cc ON p.categorie = cc.id
WHERE cs.status = 'closed' AND p.vizibil = '1'
GROUP BY pid
ORDER BY num DESC
LIMIT 0, 14

答案 3 :(得分:0)

只需删除子查询。没有帮助你。测试一下,告诉我们需要多少。

SELECT
  SUM(c.cantitate) AS num,
  p.id             AS pid,
  p.titlu          AS titlu,
  p.alias          AS alias,
  p.gramaj         AS gramaj,
  p.prettotal      AS prettotal,
  p.pretunitar     AS pretunitar,
  p.pretredus      AS pretredus,
  p.stoc           AS stoc,
  p.cant_variabila AS cant_variabila,
  p.nou            AS nou,
  p.congelat       AS congelat,
  p.cod            AS cod,
  p.poza           AS poza,
  cc.seo           AS seo
FROM produse p
  LEFT JOIN comenzi   c  ON p.id = c.produs
  LEFT JOIN cosuri    cs ON c.cos = cs.id
  LEFT JOIN categorii cc ON p.categorie = cc.id
WHERE cs.status = 'closed' AND p.vizibil = '1'
GROUP BY pid
ORDER BY num DESC
LIMIT 0, 14

当然,如果有以下字段的索引会有所帮助:

  • p.id(主键已经编入索引并且不需要创建新主键)
  • cc.id(主键已经编入索引并且不需要创建新主键)
  • cs.id(主键已经编入索引并且不需要创建新主键)
  • p.categorie
  • p.vizibil(此处潜在收益较小)
  • c.produs
  • c.cos
  • cs.status(此处潜在收益较小)
  • p.pid(根据需要订购记录而忘记该组的典型错误)