编写此查询的另一种方法

Another way to write this query

编写此查询的另一种方法是什么?

我的服务器执行这个需要很多时间:

SELECT c.id, c.franquicia_id, f.name, CONCAT(c.name,' ',c.surname) 
       contacto, c.created, DATE_FORMAT(c.created,'%d-%m-%Y') fecha 
FROM franquicias f, contacts c where f.id = c.franquicia_id 
 and c.created = (
                   select max(c2.created) 
                   from contacts c2 
                   WHERE c2.franquicia_id = c.franquicia_id
                 ) 
 and f.contract_id=2 
ORDER BY created DESC 
limit 10

这个版本的子查询只需要 运行 整个查询一次,而不是外部查询的每一行。

SELECT c.id, c.franquicia_id, f.name
   , CONCAT(c.name,' ',c.surname) AS contacto
   , c.created, DATE_FORMAT(c.created,'%d-%m-%Y') AS fecha 
FROM contacts AS c 
INNER JOIN franquicias AS f
   ON c.franquicia_id = f.id
    AND f.contract_id=2 
WHERE (c.franquicia_id, c.created) IN (
          SELECT franquicia_id, max(created) 
          FROM contacts
          GROUP BY franquicia_id
) 
ORDER BY created DESC 
LIMIT 10

或者,子查询可以在附加的 JOIN 中使用以进行过滤。

f.contract_id=2 可以放在 ONWHERE 中;但是(并且优化器可能会消除任何差异),将其保留在 ON 中可能 可能 减少在 where 中检查的行,并使以后更容易将查询转换为LEFT JOIN 如果需要查找 "most recent contacts with no f's of contract_id 2"。

注意:索引 (franquicia_id, created) 应该改进子查询,而 IN 用于它;它还应该改进 franquicia_id.

上的现有 JOIN 条件

引自此Post

I personally think the INNER JOIN is better, because it is more readable. It shows better the relations between the table. You got those relations in the join, and you do the filtering in the WHERE clause. This separation makes the query more readable.

SELECT 
    c.id, 
    c.franquicia_id, 
    f.name, 
    CONCAT(c.name,' ',c.surname) contacto, 
    c.created, 
    DATE_FORMAT(c.created,'%d-%m-%Y') fecha 
FROM franquicias f
INNER JOIN contacts c ON f.id = c.franquicia_id 
INNER JOIN 
(
    SELECT 
    C2.franquicia_id,
    MAX(C2.created) max_created
    FROM contacts C2 
    GROUP BY C2.franquicia_id
) AS maxCreatedForFrID
ON maxCreatedForFrID.franquicia_id = c.franquicia_id AND maxCreatedForFrID.max_created = c.created
WHERE f.contract_id = 2
ORDER BY created DESC
LIMIT 10;

注:

contacts table 中的复合索引 (franquicia_id,created) 可能会提高性能。

ALTER TABLE `contacts` ADD INDEX `idx_contacts_franquicia_id_created` (
    `franquicia_id`,
    `created`
);

如果franquicias包含的记录不是很多,那么下一个查询一定更有效:

SELECT c.id, c.franquicia_id, f.name, CONCAT(c.name,' ',c.surname) 
       contacto, c.created, DATE_FORMAT(c.created,'%d-%m-%Y') fecha 
FROM (
    SELECT DISTINCT MAX(c2.created) as c2_created, f2.*
    FROM contacts c2
    JOIN franquicias f2 ON f2.id = c2.franquicia_id
) f
JOIN contacts c ON f.id = c.franquicia_id
AND c.created = f.c2_created
WHERE f.contract_id=2 
ORDER BY created DESC 
limit 10