我有一个日志条目表,以及大约 100 个可能的日志代码的描述表:
CREATE TABLE `log_entries` (
`logentry_id` int(11) NOT NULL AUTO_INCREMENT,
`date` datetime NOT NULL,
`partner_id` smallint(4) NOT NULL,
`log_code` smallint(4) NOT NULL,
PRIMARY KEY (`logentry_id`),
KEY `IX_code` (`log_code`),
KEY `IX_partner_code` (`partner_id`,`log_code`)
) ENGINE=MyISAM ;
CREATE TABLE IF NOT EXISTS `log_codes` (
`log_code` smallint(4) NOT NULL DEFAULT '0',
`log_desc` varchar(255) DEFAULT NULL,
`category_overview` tinyint(1) NOT NULL DEFAULT '0',
`category_error` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`log_code`),
KEY `IX_overview_code` (`category_overview`,`log_code`),
KEY `IX_error_code` (`category_error`,`log_code`)
) ENGINE=MyISAM ;
以下查询(匹配 20k 行中的 10k)在 0.0034 秒内执行(使用LIMIT 0,20
):
SELECT log_entries.date, log_codes.log_desc FROM log_entries
INNER JOIN log_codes ON log_codes.log_code = log_entries.log_code
WHERE log_entries.partner_id = 1 AND log_codes.category_overview = 1;
但是当添加 时ORDER BY log_entries.logentry_id DESC
,这当然是必要的,它会减慢到 0.6 秒。可能是因为在 log_codes 表上使用了“使用临时”?删除索引实际上使查询执行得更快,但仍然很慢(0.3 秒)。
EXPLAIN 不带 ORDER BY 的查询输出:
+----+-------------+-------------+------+--------- --------------------+------------------+----------+- --------------+------+-------------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+-------------+-------------+------+--------- --------------------+------------------+----------+- --------------+------+-------------+ | 1 | 简单 | 日志代码 | 参考 | PRIMARY,IX_overview_code | IX_overview_code | 1 | 常量 | 56 | | | 1 | 简单 | 日志条目 | 参考 | IX_code,IX_partner_code | IX_partner_code | 7 | 常量,log_codes.log_code | 25 | 使用位置 | +----+-------------+-------------+------+--------- --------------------+------------------+----------+- --------------+------+-------------+
并包括 ORDER BY:
+----+-------------+-------------+------+--------- --------------------+------------------+----------+- ----------------------+------+------ ----------------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+-------------+-------------+------+--------- --------------------+------------------+----------+- ----------------------+------+------ ----------------+ | 1 | 简单 | 日志代码 | 参考 | PRIMARY,IX_overview_code | IX_overview_code | 1 | 常量 | 56 | 使用临时的;使用文件排序 | | 1 | 简单 | 日志条目 | 参考 | IX_code,IX_partner_code | IX_partner_code | 7 | 常量,log_codes.log_code | 25 | 使用位置 | +----+-------------+-------------+------+--------- --------------------+------------------+----------+- ----------------------+------+------ ----------------+
关于如何让这个查询执行得更快的任何提示?我不明白为什么需要“使用临时”,因为在获取和排序适当的日志条目之前应该选择日志代码?
更新@Eugen Rieck:
SELECT log_entries.date, lc.log_desc FROM log_entries INNER JOIN (SELECT log_desc, log_code FROM log_codes WHERE category_overview = 1) AS lc ON lc.log_code = log_entries.log_code WHERE log_entries.partner_id = 1 ORDER BY log_entries.logentry_id; +----+-------------+-------------+------+--------- --+------------------+----------+---- ---------------+------+--------------- ------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+-------------+-------------+------+--------- --+------------------+----------+---- ---------------+------+--------------- ------+ | 1 | 初级 | <派生2> | 全部 | 空 | 空 | 空 | 空 | 57 | 使用临时的;使用文件排序 | | 1 | 初级 | 日志条目 | 参考 | IX_code,IX_partner_code | IX_partner_code | 7 | 常量,lc.log_code | 25 | 使用位置 | | 2 | 派生 | 日志代码 | 参考 | IX_overview_code | IX_overview_code | 1 | | 56 | | +----+-------------+-------------+------+--------- --+------------------+----------+---- ---------------+------+--------------- ------+
更新@RolandoMySQLDBA:
使用我的原始索引,ORDER BY date DESC:
SELECT log_entries.date, log_codes.log_desc FROM (SELECT log_code,date FROM log_entries WHERE partner_id = 1) log_entries INNER JOIN (SELECT log_code,log_desc FROM log_codes WHERE category_overview = 1) log_codes USING (log_code) ORDER BY log_entries.date DESC; +----+-------------+-------------+------+--------- ------+------+---------+------+---- ---+------------------------------------------------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+-------------+-------------+------+--------- ------+------+---------+------+---- ---+------------------------------------------------+ | 1 | 初级 | <派生3> | 全部 | 空 | 空 | 空 | 空 | 57 | 使用临时的;使用文件排序 | | 1 | 初级 | <派生2> | 全部 | 空 | 空 | 空 | 空 | 21937 | 使用哪里;使用连接缓冲区 | | 3 | 派生 | 日志代码 | 参考 | IX_overview_code | IX_overview_code | 1 | | 56 | | | 2 | 派生 | 日志条目 | 全部 | IX_partner_code | 空 | 空 | 空 | 22787 | 使用位置 | +----+-------------+-------------+------+--------- ------+------+---------+------+---- ---+------------------------------------------------+
使用您的索引,无需排序:
SELECT log_entries.date, log_codes.log_desc FROM (SELECT log_code,date FROM log_entries WHERE partner_id = 1) log_entries INNER JOIN (SELECT log_code,log_desc FROM log_codes WHERE category_overview = 1) log_codes USING (log_code); +----+-------------+-------------+--------+-------- ---------------+-----------+---------+ ------+--------+--------------------------------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+-------------+-------------+--------+-------- ---------------+-----------+---------+ ------+--------+--------------------------------+ | 1 | 初级 | <派生3> | 全部 | 空 | 空 | 空 | 空 | 57 | | | 1 | 初级 | <派生2> | 全部 | 空 | 空 | 空 | 空 | 21937 | 使用哪里;使用连接缓冲区 | | 3 | 派生 | 日志代码 | 索引 | IX_overview_code_desc | IX_overview_code_desc | 771 | 空 | 80 | 使用哪里;使用索引 | | 2 | 派生 | 日志条目 | 索引 | IX_partner_code_date | IX_partner_code_date | 15 | 空 | 22787 | 使用哪里;使用索引 | +----+-------------+-------------+--------+-------- ---------------+-----------+---------+ ------+--------+--------------------------------+
使用您的索引,按日期 DESC 排序:
SELECT log_entries.date, log_codes.log_desc FROM (SELECT log_code,date FROM log_entries WHERE partner_id = 1) log_entries INNER JOIN (SELECT log_code,log_desc FROM log_codes WHERE category_overview = 1) log_codes USING (log_code) ORDER BY log_entries.date DESC; +----+-------------+-------------+--------+-------- ---------------+-----------+---------+ ------+--------+----------------------------------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+-------------+-------------+--------+-------- ---------------+-----------+---------+ ------+--------+----------------------------------+ | 1 | 初级 | <派生3> | 全部 | 空 | 空 | 空 | 空 | 57 | 使用临时的;使用文件排序 | | 1 | 初级 | <派生2> | 全部 | 空 | 空 | 空 | 空 | 21937 | 使用哪里;使用连接缓冲区 | | 3 | 派生 | 日志代码 | 索引 | IX_overview_code_desc | IX_overview_code_desc | 771 | 空 | 80 | 使用哪里;使用索引 | | 2 | 派生 | 日志条目 | 索引 | IX_partner_code_date | IX_partner_code_date | 15 | 空 | 22787 | 使用哪里;使用索引 | +----+-------------+-------------+--------+-------- ---------------+-----------+---------+ ------+--------+----------------------------------+
更新@Joe Stefanelli:
SELECT log_entries.date, log_codes.log_desc FROM log_entries INNER JOIN log_codes ON log_codes.log_code = log_entries.log_code WHERE log_entries.partner_id = 1 AND log_codes.category_overview = 1 ORDER BY date DESC; +----+-------------+-------------+------+--------- -----------------+-----------------+---------+---- ----------------------+------+-------- --------------------------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+-------------+-------------+------+--------- -----------------+-----------------+---------+---- ----------------------+------+-------- --------------------------+ | 1 | 简单 | 日志代码 | 全部 | PRIMARY,IX_code_overview | 空 | 空 | 空 | 80 | 使用哪里;使用临时的;使用文件排序 | | 1 | 简单 | 日志条目 | 参考 | IX_code,IX_code_partner | IX_code_partner | 7 | log_codes.log_code,const | 25 | 使用位置 | +----+-------------+-------------+------+--------- -----------------+-----------------+---------+---- ----------------------+------+-------- --------------------------+