带有 SUM 的 MySQL LEFT JOIN 很慢

Posted

技术标签:

【中文标题】带有 SUM 的 MySQL LEFT JOIN 很慢【英文标题】:MySQL LEFT JOIN with SUM is slow 【发布时间】:2012-09-07 03:39:06 【问题描述】:

我需要一些想法来优化这个查询:

SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 /* Active Users Only */
    GROUP BY U.Id

关于表格的一些信息:

    users 表:10,000+ 条记录 payments 表:2,000,000+ 条记录,索引在 UserId 列上

查询最多需要 2 分钟。通过查询查询,我发现SUM函数是查询慢的原因。尝试在没有SUM 的情况下执行查询只需不到 2 秒。

这个查询还有改进的余地吗?谢谢

编辑 1

这是我使用EXPLAIN时得到的:

id  select_type table   type    possible_keys   key     key_len     ref             rows    Extra
1   SIMPLE      U       ALL                                                         8304    Using where; Using temporary; Using filesort
1   SIMPLE      P       ref     UserId          UserId  5           Database.U.Id   361     ""

索引payments.UserId 正在查询中使用。对此有什么想法吗?

编辑 2 表信息:

users   "CREATE TABLE `users` (
  `Id` int(11) NOT NULL auto_increment,
  `StatusId` int(11) default NULL,
  `Name` varchar(60) default NULL,
  `TimeZone` varchar(100) default NULL,
  PRIMARY KEY  (`Id`),
  KEY `StatusId` (`StatusId`),
  CONSTRAINT `FK_User_Status` FOREIGN KEY (`StatusId`) REFERENCES `userStatus` (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8"

payments    "CREATE TABLE `payments` (
  `Id` int(11) NOT NULL auto_increment,
  `UserId` int(11) default NULL,  
  `Description` varchar(200) default NULL,
  `Debit` decimal(11,2) default NULL,
  `Credit` decimal(11,2) default NULL,
  `Date` datetime default NULL,
  PRIMARY KEY  (`Id`),
  KEY `UserId` (`UserId`),
  CONSTRAINT `FK_Payment_User` FOREIGN KEY (`UserId`) REFERENCES `users` (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8"

【问题讨论】:

嗨,kael,您是否在此列上编制索引? payments.UserIdusers.Id 嗨,约翰,是的,它们都已编入索引。 users.Id 是主键,我认为它已经是唯一索引了。 payments.UserId 怎么样? 运行explain,你可能会明白为什么会有这样的cost @KaeL 很简单,只需在查询前写上explain (read more...) 【参考方案1】:

如果添加以下索引:

CREATE INDEX ix_status ON users (StatusId, Id);
CREATE INDEX ix_userid ON payments (UserId, Credit, Debit);

并添加FORCE INDEX选项:

SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 /* Active Users Only */
    GROUP BY
        U.Id;

您的查询几乎肯定会执行得更好。

【讨论】:

谢谢罗斯,我试试这个。 对不起Ross,创建索引并使用FORCE INDEX调整查询,执行时间仍然超过2分钟。感谢您的想法 +1 :)【参考方案2】:

根据这个link,我无法加速SUM 函数。这里的主要问题是我选择了大量的记录。

我想重新设计users 表,添加一个新列,如TotalPayment,它将包含credit 减去debit 表中debit 的总数。我知道它违反了数据库规范化规则,但我想这次重新设计是为了节省性能。

非常感谢你们的帮助。

【讨论】:

我遇到过这样的问题,当我加入的字段的字符集/排序规则不同时。如果一个是latin,另一个是utf8,则运行亚秒级查询将需要5+ 分钟。如果INT 中有一个字段,而另一个字段是INT UNSIGNED,您也可能会遇到这种情况。要识别这些类型的问题,您能否包含SHOW CREATE TABLE users; SHOW CREATE TABLE payments; 的输出? 谢谢罗斯,在我的问题中添加了表格代码,抱歉回复晚了。 Kael,您的性能问题出在其他地方(例如在您的 my.cnf 文件中)。我创建了一个userspayments 表,用20,000 和2,000,000 条记录加载它们,并在16.1 秒内运行您的查询(平均超过5 次运行)。添加索引并添加 FORCE INDEX 选项后,查询运行时间为 0.9 秒(平均) 哇,太好了,我会检查你的答案。非常感谢! :)【参考方案3】:

Kael,这是我运行的脚本及其输出,用于显示我在第一个答案中提供的索引和查询,将查询时间从大约 14.3 秒减少到仅 0.75 秒:

DROP TABLE IF EXISTS payments;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS userStatus;

CREATE TABLE userStatus (
    Id int(11) NOT NULL auto_increment,
    PRIMARY KEY  (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE users (
    Id int(11) NOT NULL auto_increment,
    StatusId int(11) default NULL,
    Name varchar(60) default NULL,
    TimeZone varchar(100) default NULL,
    PRIMARY KEY  (Id),
    KEY StatusId (StatusId),
    CONSTRAINT FK_User_Status FOREIGN KEY (StatusId) REFERENCES userStatus (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE payments (
    Id int(11) NOT NULL auto_increment,
    UserId int(11) default NULL,  
    Description varchar(200) default NULL,
    Debit decimal(11,2) default NULL,
    Credit decimal(11,2) default NULL,
    Date datetime default NULL,
    PRIMARY KEY  (Id),
    KEY UserId (UserId),
    CONSTRAINT FK_Payment_User FOREIGN KEY (UserId) REFERENCES users (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS ids;
CREATE TABLE IF NOT EXISTS ids (
    id INT UNSIGNED AUTO_INCREMENT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=MyISAM; -- must be MyISAM
INSERT INTO ids SET id = NULL; # inserts a 1
UPDATE ids SET id=0;
ALTER TABLE ids AUTO_INCREMENT=1;
INSERT INTO ids SELECT NULL FROM ids; #      1      1
INSERT INTO ids SELECT NULL FROM ids; #      2      2
INSERT INTO ids SELECT NULL FROM ids; #      4      4
INSERT INTO ids SELECT NULL FROM ids; #      8      8
INSERT INTO ids SELECT NULL FROM ids; #     10     16
INSERT INTO ids SELECT NULL FROM ids; #     20     32
INSERT INTO ids SELECT NULL FROM ids; #     40     64
INSERT INTO ids SELECT NULL FROM ids; #     80    128
INSERT INTO ids SELECT NULL FROM ids; #    100    256
INSERT INTO ids SELECT NULL FROM ids; #    200    512
INSERT INTO ids SELECT NULL FROM ids; #    400  1,024
INSERT INTO ids SELECT NULL FROM ids; #    800  2,048
INSERT INTO ids SELECT NULL FROM ids; #   1000  4,096
INSERT INTO ids SELECT NULL FROM ids; #   2000  8,192
INSERT INTO ids SELECT NULL FROM ids; #   4000 16,384

INSERT INTO 
userStatus
(id)
SELECT
id
FROM
ids
WHERE
id > 0
ORDER BY
id
LIMIT 2;

INSERT INTO 
users
(Id, StatusId)
SELECT
id,
IF(RAND() < .9, 1, 2) -- 90% of users are 'Active'
FROM
ids
WHERE
id > 0 AND
id <= 20000
ORDER BY
id;

INSERT INTO
payments
(Id, UserId, Debit, Credit, `Date`)
SELECT
NULL,
i1.id,
ROUND(RAND() * 1000, 2),
ROUND(RAND() * 1000, 2),
NOW() - INTERVAL FLOOR(RAND() * 86400 * 1000) SECOND
FROM
ids i1,
ids i2 
WHERE
i1.id > 0 AND
i1.id <= 20000 AND
i2.id < 100
ORDER BY
RAND();

EXPLAIN
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 /* Active Users Only */
    GROUP BY U.Id;

SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 /* Active Users Only */
    GROUP BY U.Id;

SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 /* Active Users Only */
    GROUP BY U.Id;

SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 /* Active Users Only */
    GROUP BY U.Id;

CREATE INDEX ix_status ON users (StatusId, Id);
CREATE INDEX ix_userid ON payments (UserId, Credit, Debit);

EXPLAIN
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 /* Active Users Only */
    GROUP BY
        U.Id;

SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 /* Active Users Only */
    GROUP BY
        U.Id;

SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 /* Active Users Only */
    GROUP BY
        U.Id;

SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 /* Active Users Only */
    GROUP BY
        U.Id; 

这是输出:

[ross@titanv ~]$ mysql -vvv < ex.sql temp
--------------
DROP TABLE IF EXISTS payments
--------------

Query OK, 0 rows affected (0.01 sec)

--------------
DROP TABLE IF EXISTS users
--------------

Query OK, 0 rows affected (0.00 sec)

--------------
DROP TABLE IF EXISTS userStatus
--------------

Query OK, 0 rows affected (0.01 sec)

--------------
CREATE TABLE userStatus (
        Id int(11) NOT NULL auto_increment,
        PRIMARY KEY  (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
--------------

Query OK, 0 rows affected (0.01 sec)

--------------
CREATE TABLE users (
        Id int(11) NOT NULL auto_increment,
        StatusId int(11) default NULL,
        Name varchar(60) default NULL,
        TimeZone varchar(100) default NULL,
        PRIMARY KEY  (Id),
        KEY StatusId (StatusId),
        CONSTRAINT FK_User_Status FOREIGN KEY (StatusId) REFERENCES userStatus (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
--------------

Query OK, 0 rows affected (0.00 sec)

--------------
CREATE TABLE payments (
        Id int(11) NOT NULL auto_increment,
        UserId int(11) default NULL,  
        Description varchar(200) default NULL,
        Debit decimal(11,2) default NULL,
        Credit decimal(11,2) default NULL,
        Date datetime default NULL,
        PRIMARY KEY  (Id),
        KEY UserId (UserId),
        CONSTRAINT FK_Payment_User FOREIGN KEY (UserId) REFERENCES users (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
--------------

Query OK, 0 rows affected (0.01 sec)

--------------
DROP TABLE IF EXISTS ids
--------------

Query OK, 0 rows affected (0.00 sec)

--------------
CREATE TABLE IF NOT EXISTS ids (
        id INT UNSIGNED AUTO_INCREMENT NOT NULL,
        PRIMARY KEY (id)
) ENGINE=MyISAM
--------------

Query OK, 0 rows affected (0.01 sec)

--------------
INSERT INTO ids SET id = NULL
--------------

Query OK, 1 row affected (0.00 sec)

--------------
UPDATE ids SET id=0
--------------

Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

--------------
ALTER TABLE ids AUTO_INCREMENT=1
--------------

Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 8 rows affected (0.00 sec)
Records: 8  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 16 rows affected (0.00 sec)
Records: 16  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 32 rows affected (0.01 sec)
Records: 32  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 64 rows affected (0.00 sec)
Records: 64  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 128 rows affected (0.00 sec)
Records: 128  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 256 rows affected (0.00 sec)
Records: 256  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 512 rows affected (0.00 sec)
Records: 512  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 1024 rows affected (0.00 sec)
Records: 1024  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 2048 rows affected (0.00 sec)
Records: 2048  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 4096 rows affected (0.01 sec)
Records: 4096  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 8192 rows affected (0.01 sec)
Records: 8192  Duplicates: 0  Warnings: 0

--------------
INSERT INTO ids SELECT NULL FROM ids
--------------

Query OK, 16384 rows affected (0.02 sec)
Records: 16384  Duplicates: 0  Warnings: 0

--------------
INSERT INTO 
userStatus
(id)
SELECT
id
FROM
ids
WHERE
id > 0
ORDER BY
id
LIMIT 2
--------------

Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

--------------
INSERT INTO 
users
(Id, StatusId)
SELECT
id,
IF(RAND() < .9, 1, 2) 
FROM
ids
WHERE
id > 0 AND
id <= 20000
ORDER BY
id
--------------

Query OK, 20000 rows affected (0.11 sec)
Records: 20000  Duplicates: 0  Warnings: 0

--------------
INSERT INTO
payments
(Id, UserId, Debit, Credit, `Date`)
SELECT
NULL,
i1.id,
ROUND(RAND() * 1000, 2),
ROUND(RAND() * 1000, 2),
NOW() - INTERVAL FLOOR(RAND() * 86400 * 1000) SECOND
FROM
ids i1,
ids i2 
WHERE
i1.id > 0 AND
i1.id <= 20000 AND
i2.id < 100
ORDER BY
RAND()
--------------

Query OK, 2000000 rows affected (21.52 sec)
Records: 2000000  Duplicates: 0  Warnings: 0

--------------
EXPLAIN
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 
    GROUP BY U.Id
--------------

+----+-------------+-------+------+---------------+----------+---------+-----------+-------+-------------+
| id | select_type | table | type | possible_keys | key      | key_len | ref       | rows  | Extra       |
+----+-------------+-------+------+---------------+----------+---------+-----------+-------+-------------+
|  1 | SIMPLE      | U     | ref  | StatusId      | StatusId | 5       | const     | 10274 | Using where |
|  1 | SIMPLE      | P     | ref  | UserId        | UserId   | 5       | temp.U.Id |     1 |             |
+----+-------------+-------+------+---------------+----------+---------+-----------+-------+-------------+
2 rows in set (0.00 sec)

--------------
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 
    GROUP BY U.Id
--------------

+-------+------+--------------+-------------+
| Id    | Name | CreditAmount | DebitAmount |
+-------+------+--------------+-------------+
|     1 | NULL |     47824.73 |    49580.71 |
|     2 | NULL |     46426.02 |    52019.69 |
...
| 19999 | NULL |     50041.10 |    47696.88 |
| 20000 | NULL |     51923.69 |    50349.38 |
+-------+------+--------------+-------------+
18057 rows in set (14.60 sec)

--------------
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 
    GROUP BY U.Id
--------------

+-------+------+--------------+-------------+
| Id    | Name | CreditAmount | DebitAmount |
+-------+------+--------------+-------------+
|     1 | NULL |     47824.73 |    49580.71 |
|     2 | NULL |     46426.02 |    52019.69 |
...
| 19999 | NULL |     50041.10 |    47696.88 |
| 20000 | NULL |     51923.69 |    50349.38 |
+-------+------+--------------+-------------+
18057 rows in set (14.10 sec)

--------------
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM users U
    LEFT JOIN payments P ON P.UserId = U.Id
    WHERE U.StatusId = 1 
    GROUP BY U.Id
--------------

+-------+------+--------------+-------------+
| Id    | Name | CreditAmount | DebitAmount |
+-------+------+--------------+-------------+
|     1 | NULL |     47824.73 |    49580.71 |
|     2 | NULL |     46426.02 |    52019.69 |
...
| 19999 | NULL |     50041.10 |    47696.88 |
| 20000 | NULL |     51923.69 |    50349.38 |
+-------+------+--------------+-------------+
18057 rows in set (14.17 sec)

--------------
CREATE INDEX ix_status ON users (StatusId, Id)
--------------

Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

--------------
CREATE INDEX ix_userid ON payments (UserId, Credit, Debit)
--------------

Query OK, 0 rows affected (5.09 sec)
Records: 0  Duplicates: 0  Warnings: 0

--------------
EXPLAIN
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 
    GROUP BY
        U.Id
--------------

+----+-------------+-------+------+---------------+-----------+---------+-----------+-------+-------------+
| id | select_type | table | type | possible_keys | key       | key_len | ref       | rows  | Extra       |
+----+-------------+-------+------+---------------+-----------+---------+-----------+-------+-------------+
|  1 | SIMPLE      | U     | ref  | ix_status     | ix_status | 5       | const     | 10274 | Using where |
|  1 | SIMPLE      | P     | ref  | ix_userid     | ix_userid | 5       | temp.U.Id | 10002 | Using index |
+----+-------------+-------+------+---------------+-----------+---------+-----------+-------+-------------+
2 rows in set (0.00 sec)

--------------
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 
    GROUP BY
        U.Id
--------------

+-------+------+--------------+-------------+
| Id    | Name | CreditAmount | DebitAmount |
+-------+------+--------------+-------------+
|     1 | NULL |     47824.73 |    49580.71 |
|     2 | NULL |     46426.02 |    52019.69 |
...
| 19999 | NULL |     50041.10 |    47696.88 |
| 20000 | NULL |     51923.69 |    50349.38 |
+-------+------+--------------+-------------+
18057 rows in set (0.75 sec)

--------------
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 
    GROUP BY
        U.Id
--------------

+-------+------+--------------+-------------+
| Id    | Name | CreditAmount | DebitAmount |
+-------+------+--------------+-------------+
|     1 | NULL |     47824.73 |    49580.71 |
|     2 | NULL |     46426.02 |    52019.69 |
...
| 19999 | NULL |     50041.10 |    47696.88 |
| 20000 | NULL |     51923.69 |    50349.38 |
+-------+------+--------------+-------------+
18057 rows in set (0.75 sec)

--------------
SELECT U.Id
    , U.Name
    , SUM(P.Credit) AS CreditAmount
    , SUM(P.Debit) AS DebitAmount
    FROM 
        users U FORCE INDEX (ix_status)
    LEFT JOIN 
        payments P FORCE INDEX (ix_userid) ON P.UserId = U.Id
    WHERE 
        U.StatusId = 1 
    GROUP BY
        U.Id
--------------

+-------+------+--------------+-------------+
| Id    | Name | CreditAmount | DebitAmount |
+-------+------+--------------+-------------+
|     1 | NULL |     47824.73 |    49580.71 |
|     2 | NULL |     46426.02 |    52019.69 |
...
| 19999 | NULL |     50041.10 |    47696.88 |
| 20000 | NULL |     51923.69 |    50349.38 |
+-------+------+--------------+-------------+
18057 rows in set (0.75 sec)

Bye

【讨论】:

我会检查一下。再次感谢! +1 抱歉更新晚了,我正在处理不同的问题。我能够对此进行测试,但仍然得到相同的结果。查找 my.cnf 文件以检查优化设置。这对我帮助很大,经过更多测试后我会接受。谢谢! 对不起,罗斯,不能接受你的回答,但我确实投了赞成票,因为它对我帮助很大。我们无法更改 my.cnf 文件上的任何 properties/variables,我们的服务器不允许这样做。谢谢您的帮助! :D 我不明白。您的问题是“优化我的查询”,而我的回答就是这样做的。如果答案在您的系统上不起作用,我建议在另一个系统上尝试(甚至可能是 sqlfiddle.com),因为您正在测试的系统似乎存在与您尝试优化的查询无关的性能问题。而您确实接受的答案并没有回答问题。 明白你的意思罗斯,我已经在我们的本地服务器上测试了你的答案,甚至在我们的生产服务器上[由于性能问题而无法工作],但我们仅限于修改服务器设置。我接受了这个答案,因为我正在考虑改进查询的其他方法,不仅仅是查询本身,还有设计。

以上是关于带有 SUM 的 MySQL LEFT JOIN 很慢的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:带有 JOIN 的 SUM() 返回不正确的值

MySQL LEFT JOIN with SUM before a date and SUM before and at that date

MySQL:带有LEFT JOIN的GROUP_CONCAT

带有Left Join的Mysql查询太慢了

带有 LEFT JOIN 和 GROUP BY 的 COUNT(*) 在 MySQL 中包含 NULL

SQL语句多表left join SUM出现的重复数据问题!