MySQL 连接 3 个表 运行 非常慢
MySQL join across 3 tables running very slowly
我正在显示一页日记事件以及客户详细信息和他们案例的最新记录。
我正在使用 Laravel 的查询生成器,我现在的查询是:
$data['events'] = DB::table('events')
->where('cancelled', 0)
->where('complete', 0)
->join('clients', 'events.clientid', '=', 'clients.id')
->join('notes', function ($join) {
$join->on('events.clientid', '=', 'notes.clientid')
->on('notes.created_at', '=', DB::raw('(select created_at from notes where clientid = clients.id ORDER BY created_at DESC LIMIT 1)'));
})
->select('events.*', 'clients.firstname', 'clients.surname', 'notes.note')
->orderBy('eventtime', 'asc')->paginate(75); //Load events sorted by time
这样输出的SQL是:
select `events`.*, `clients`.`firstname`, `clients`.`surname`, `notes`.`note` from `events`
inner join `clients` on `events`.`clientid` = `clients`.`id`
inner join `notes` on `events`.`clientid` = `notes`.`clientid`
and `notes`.`created_at` = (
select created_at from notes where clientid = clients.id ORDER BY created_at DESC LIMIT 1)
where `cancelled` = ? and `complete` = ? order by `eventtime` asc
查询运行完美,但随着 table 大小的增加,查询变得非常慢。完成大约需要 30 秒,并且是唯一的查询 运行 如此缓慢。
有没有更好的方法来组织联接?在单独的查询中获取最新的注释是否有意义?
非常感谢,
山姆
不确定,但您可以尝试下面的查询,因为如果注释 table 庞大 table-
,您可以避免在子查询中对其进行反向排序
SELECT `events`.*, `clients`.`firstname`, `clients`.`surname`, `notes`.`note`
FROM `events`
INNER JOIN `clients` ON `events`.`clientid` = `clients`.`id`
INNER JOIN `notes` ON `events`.`clientid` = `notes`.`clientid`
AND `notes`.`created_at` =
(
SELECT MAX(created_at)
FROM notes
WHERE clientid = clients.id
)
WHERE `cancelled` = ? AND `complete` = ?
ORDER BY `eventtime` ASC
假设所有连接字段和 created_at 字段都有索引。
此外,如果事件 table 包含一些 text/blob 或 long varchar 类型的列,那么您应该排除它们(如果不需要,因为您正在使用事件)。*
这些索引会很有帮助
events(clientid)
clients(id)
notes(clientid,created_at)
notes(created_at,clientid)
注意,4 可能是
notes(created_at,clientid,cacelled,complete,eventtime)
我不会在其中添加注释,使其成为覆盖索引,因为注释会太宽。
求解步骤:
- 更改您的查询
这就是您的查询:
select `events`.*, `clients`.`firstname`, `clients`.`surname`, `notes`.`note` from `events`
inner join `clients` on `events`.`clientid` = `clients`.`id`
inner join `notes` on `events`.`clientid` = `notes`.`clientid`
and `notes`.`created_at` = (
select created_at from notes where clientid = clients.id ORDER BY created_at DESC LIMIT 1)
where `cancelled` = ? and `complete` = ? order by `eventtime` asc
让我们这样改:
select `events`.*, `clients`.`firstname`, `clients`.`surname`, `notes`.`note` from `events`
inner join `clients` on `events`.`clientid` = `clients`.`id`
inner join `notes` on `events`.`clientid` = `notes`.`clientid`
and `notes`.`id` = (SELECT MAX(id) FROM notes WHERE clientid = clients.id)
where `cancelled` = ? and `complete` = ? order by `eventtime` asc
如果您想从笔记中获取最新记录,则无需按 created_at 排序并获取最新记录。如果您不手动编辑 tables,那么 MAX(id) 和 latest created_at 都将指示最新记录。
- 添加索引
索引总是有助于数据库避免在搜索数据时获取整个 table。
因此,当您加入或进行查询时,它会在内存中收集所有具有相关字段条件的记录,然后加入数据数组。
添加索引将帮助数据库首先关闭所有快速找到所需的数据。
索引有助于数据库引擎在针数据存在的二进制文件中进行偏移
所以让我们添加索引:
ALTER TABLE `events` ADD INDEX `clientid` (`clientid`);
ALTER TABLE `notes` ADD INDEX `clientid` (`clientid`);
ALTER TABLE `events` ADD INDEX `cancelled` (`cancelled`);
ALTER TABLE `events` ADD INDEX `complete` (`complete`);
ALTER TABLE `events` ADD INDEX `cancelled_complete` (`cancelled`, `cancelled`);
ALTER TABLE `events` ADD INDEX `eventtime` (`eventtime`);
就这些了(:
p.s。大多数 laravel 开发人员的主要问题是他们在编写迁移模式时忘记设置索引。 http://laravel.com/docs/5.1/migrations#creating-indexes
我正在显示一页日记事件以及客户详细信息和他们案例的最新记录。
我正在使用 Laravel 的查询生成器,我现在的查询是:
$data['events'] = DB::table('events')
->where('cancelled', 0)
->where('complete', 0)
->join('clients', 'events.clientid', '=', 'clients.id')
->join('notes', function ($join) {
$join->on('events.clientid', '=', 'notes.clientid')
->on('notes.created_at', '=', DB::raw('(select created_at from notes where clientid = clients.id ORDER BY created_at DESC LIMIT 1)'));
})
->select('events.*', 'clients.firstname', 'clients.surname', 'notes.note')
->orderBy('eventtime', 'asc')->paginate(75); //Load events sorted by time
这样输出的SQL是:
select `events`.*, `clients`.`firstname`, `clients`.`surname`, `notes`.`note` from `events`
inner join `clients` on `events`.`clientid` = `clients`.`id`
inner join `notes` on `events`.`clientid` = `notes`.`clientid`
and `notes`.`created_at` = (
select created_at from notes where clientid = clients.id ORDER BY created_at DESC LIMIT 1)
where `cancelled` = ? and `complete` = ? order by `eventtime` asc
查询运行完美,但随着 table 大小的增加,查询变得非常慢。完成大约需要 30 秒,并且是唯一的查询 运行 如此缓慢。
有没有更好的方法来组织联接?在单独的查询中获取最新的注释是否有意义?
非常感谢,
山姆
不确定,但您可以尝试下面的查询,因为如果注释 table 庞大 table-
,您可以避免在子查询中对其进行反向排序SELECT `events`.*, `clients`.`firstname`, `clients`.`surname`, `notes`.`note`
FROM `events`
INNER JOIN `clients` ON `events`.`clientid` = `clients`.`id`
INNER JOIN `notes` ON `events`.`clientid` = `notes`.`clientid`
AND `notes`.`created_at` =
(
SELECT MAX(created_at)
FROM notes
WHERE clientid = clients.id
)
WHERE `cancelled` = ? AND `complete` = ?
ORDER BY `eventtime` ASC
假设所有连接字段和 created_at 字段都有索引。
此外,如果事件 table 包含一些 text/blob 或 long varchar 类型的列,那么您应该排除它们(如果不需要,因为您正在使用事件)。*
这些索引会很有帮助
events(clientid)
clients(id)
notes(clientid,created_at)
notes(created_at,clientid)
注意,4 可能是
notes(created_at,clientid,cacelled,complete,eventtime)
我不会在其中添加注释,使其成为覆盖索引,因为注释会太宽。
求解步骤:
- 更改您的查询
这就是您的查询:
select `events`.*, `clients`.`firstname`, `clients`.`surname`, `notes`.`note` from `events`
inner join `clients` on `events`.`clientid` = `clients`.`id`
inner join `notes` on `events`.`clientid` = `notes`.`clientid`
and `notes`.`created_at` = (
select created_at from notes where clientid = clients.id ORDER BY created_at DESC LIMIT 1)
where `cancelled` = ? and `complete` = ? order by `eventtime` asc
让我们这样改:
select `events`.*, `clients`.`firstname`, `clients`.`surname`, `notes`.`note` from `events`
inner join `clients` on `events`.`clientid` = `clients`.`id`
inner join `notes` on `events`.`clientid` = `notes`.`clientid`
and `notes`.`id` = (SELECT MAX(id) FROM notes WHERE clientid = clients.id)
where `cancelled` = ? and `complete` = ? order by `eventtime` asc
如果您想从笔记中获取最新记录,则无需按 created_at 排序并获取最新记录。如果您不手动编辑 tables,那么 MAX(id) 和 latest created_at 都将指示最新记录。
- 添加索引
索引总是有助于数据库避免在搜索数据时获取整个 table。
因此,当您加入或进行查询时,它会在内存中收集所有具有相关字段条件的记录,然后加入数据数组。
添加索引将帮助数据库首先关闭所有快速找到所需的数据。
索引有助于数据库引擎在针数据存在的二进制文件中进行偏移
所以让我们添加索引:
ALTER TABLE `events` ADD INDEX `clientid` (`clientid`);
ALTER TABLE `notes` ADD INDEX `clientid` (`clientid`);
ALTER TABLE `events` ADD INDEX `cancelled` (`cancelled`);
ALTER TABLE `events` ADD INDEX `complete` (`complete`);
ALTER TABLE `events` ADD INDEX `cancelled_complete` (`cancelled`, `cancelled`);
ALTER TABLE `events` ADD INDEX `eventtime` (`eventtime`);
就这些了(:
p.s。大多数 laravel 开发人员的主要问题是他们在编写迁移模式时忘记设置索引。 http://laravel.com/docs/5.1/migrations#creating-indexes