简体   繁体   English

如何使用多个 JOIN 加快 SQL 查询?

[英]How to speed up SQL query with multiple JOINs?

The below SQL query took 8.0943 seconds to execute.下面的 SQL 查询执行时间为 8.0943 秒。 Is there a better way to speed this up?有没有更好的方法来加快速度?

SELECT 
       e.idno, e.estatus,
       p.idno, p.id, p.time, p.date, p.employee, p.status, p.comment
       FROM e_company_data e
       INNER JOIN people_attendance p ON p.idno = e.idno
       WHERE p.id = (SELECT MAX(id) FROM people_attendance p1
                            WHERE p1.idno = p.idno)
       AND e.estatus = 1 ORDER BY e.idno

I have already indexed the following.我已经索引了以下内容。

Table: people_attendance Columns: idno, date, time, employee, status, comment表:people_attendance 列:idno、日期、时间、员工、状态、评论

Table: e_company_data Columns: idno, estatus表:e_company_data 列:idno、estatus

I might have done wrong on the indexes.我可能在索引上做错了。 Any help would be greatly appreciated.任何帮助将不胜感激。 Thanks.谢谢。

(From pastebin) (来自pastebin)

CREATE TABLE `people_attendance` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `reference` int(11) DEFAULT NULL,
 `idno` varchar(11) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 `date` date DEFAULT NULL,
 `employee` varchar(80) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 `status` varchar(15) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 `time` time DEFAULT NULL,
 `comment` varchar(80) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 `reason` varchar(80) COLLATE utf8mb4_unicode_ci NOT NULL,
 `counter` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `idxidno` (`idno`),
 KEY `idxattendance` (`employee`,`status`,`date`,`time`,`comment`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=12888 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

CREATE TABLE `e_company_data` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `reference` int(11) NOT NULL,
 `company` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT \'\',
 `department` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT \'0\',
 `jobposition` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT \'\',
 `companyemail` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT \'\',
 `idno` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT \'\',
 `pin` varchar(4) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 `startdate` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT \'\',
 `dateregularized` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT \'\',
 `reason` varchar(455) COLLATE utf8mb4_unicode_ci DEFAULT \'\',
 `leaveprivilege` int(11) DEFAULT NULL,
 `estatus` int(2) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `idxcompdata` (`idno`,`department`,`estatus`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=130 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

Possibly using window functions:可能使用 window 功能:

SELECT e.idno, e.estatus,
       p.idno, p.id, p.time, p.date, p.employee, p.status, p.comment
FROM e_company_data e JOIN
     (SELECT p.*, ROW_NUMBER() OVER (PARTITION BY p.idno ORDER BY p.id DESC) as seqnum
      FROM people_attendance p
     ) p
     ON p.idno = e.idno AND seqnum = 1
WHERE e.estatus = 1
ORDER BY e.idno;

This should benefit from indexes on people_attendance(idno, id desc) and e_company_data(status, idno) .这应该受益于people_attendance(idno, id desc)e_company_data(status, idno)上的索引。

EDIT:编辑:

For your version of the query:对于您的查询版本:

SELECT e.idno, e.estatus,
       p.idno, p.id, p.time, p.date, p.employee, p.status, p.comment
FROM e_company_data e JOIN
     people_attendance p
     ON p.idno = e.idno
WHERE p.id = (SELECT MAX(p2.id)
              FROM people_attendance p2
              WHERE p2.idno = p.idno
             ) AND
      e.estatus = 1
ORDER BY e.idno;

I would recommend indexes on e_company_data(status, idno) and people_attendance(idno, id) .我会推荐e_company_data(status, idno)people_attendance(idno, id)的索引。

Give this a try:试试这个:

SELECT  e.idno, e.estatus, p.idno, p.id, p.time, p.date, p.employee,
        p.status, p.comment
    FROM  ( SELECT idno, MAX(id) AS last_id
                 FROM people_attendance
                 GROUP BY idno ) AS x
    JOIN  e_company_data e  USING(idno)
    JOIN  people_attendance p  ON p.id = x.last_id
    WHERE  e.estatus = 1
    ORDER BY  e.idno

The principle is to turn the correlated subquery into a derived table.原理是将相关子查询变成派生表。 Instead of 130 probes, it is one quick scan of a covering INDEX(idno, id) to get the 130 rows.它不是 130 次探测,而是一次快速扫描覆盖INDEX(idno, id)以获得 130 行。 After that, the rest is efficient JOINs.之后,rest 是高效的 JOIN。

Also, add INDEX(idno, status) (in either order) to e_company_data .此外,将INDEX(idno, status) (以任意顺序)添加到e_company_data

In addition to Rick James answer, keep in mind that your query is slow on agregate function "SELECT MAX(id)".除了 Rick James 的回答,请记住,您的查询在聚合 function“SELECT MAX(id)”上很慢。 Think about to add field which on update would keep max(id).考虑添加更新时将保留 max(id) 的字段。

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

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