【发布时间】:2012-03-21 22:29:34
【问题描述】:
我不确定如何制作一个可以正确捕获类别/log_code 的体面的索引。也许我还需要更改我的查询?感谢您的意见!
所有 SELECTS 包含:
SELECT logentry_id, date, log_codes.log_desc FROM log_entries
INNER JOIN log_codes ON log_entries.log_code = log_codes.log_code
ORDER BY logentry_id DESC
查询可以如上所述,但通常有一个 WHERE 来指定要显示的 log_codes 类别,和/或合作伙伴,和/或客户。 WHERE 示例:
WHERE partner_id = 1
WHERE log_codes.category_overview = 1
WHERE partner_id = 1 AND log_codes.category_overview = 1
WHERE partner_id = 1 AND customer_id = 1 AND log_codes.category_overview = 1
数据库结构:
CREATE TABLE IF NOT EXISTS `log_codes` (
`log_code` smallint(6) NOT NULL,
`log_desc` varchar(255),
`category_mail` tinyint(1) NOT NULL,
`category_overview` tinyint(1) NOT NULL,
`category_cron` tinyint(1) NOT NULL,
`category_documents` tinyint(1) NOT NULL,
`category_error` tinyint(1) NOT NULL,
PRIMARY KEY (`log_code`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `log_entries` (
`logentry_id` int(11) NOT NULL AUTO_INCREMENT,
`date` datetime NOT NULL,
`log_code` smallint(6) NOT NULL,
`partner_id` int(11) NOT NULL,
`customer_id` int(11) NOT NULL,
PRIMARY KEY (`logentry_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
编辑:在字段上添加索引,这里是 SHOW INDEXES 的输出:
+-----------+------------+----------- ---------+-------------+---------- -+-----------+-------------+----------+--------+-- ----+------------+---------+----------------+ |表 |非唯一 |键名 | Seq_in_index |列名 |整理 |基数|子部分 |包装 |空 |索引类型 |评论 |索引评论 | +-----------+------------+------------------------+ --------------+-----------+------------ +-------------+---------+--------+------+-------- ----+----------+--------------+ |日志代码 | 0 |初级 | 1 |日志代码 |一个 | 97 |空 |空 | | BTREE | | | |日志代码 | 1 |类别邮件 | 1 |类别邮件 |一个 | 1 |空 |空 | | BTREE | | | |日志代码 | 1 |类别概述 | 1 |类别概述 |一个 | 1 |空 |空 | | BTREE | | | |日志代码 | 1 | category_cron | 1 | category_cron |一个 | 1 |空 |空 | | BTREE | | | |日志代码 | 1 |类别文件 | 1 |类别文件 |一个 | 1 |空 |空 | | BTREE | | | |日志代码 | 1 |类别错误 | 1 |类别错误 |一个 | 1 |空 |空 | | BTREE | | | +-----------+------------+------------------------+ --------------+-----------+------------ +-------------+---------+--------+------+-------- ----+----------+--------------+ +-------------+------------+--------------+-------- --------+--------------+------------+--------------+- ---------+--------+------+------------+---------+- --------------+ |表 |非唯一 |键名 | Seq_in_index |列名 |整理 |基数|子部分 |包装 |空 |索引类型 |评论 |索引评论 | +-------------+------------+--------------+-------- --------+--------------+------------+--------------+- ---------+--------+------+------------+---------+- --------------+ |日志条目 | 0 |初级 | 1 | logentry_id |一个 | 163020 |空 |空 | | BTREE | | | |日志条目 | 1 |日志代码 | 1 |日志代码 |一个 | 90 |空 |空 | | BTREE | | | |日志条目 | 1 |合作伙伴 ID | 1 |合作伙伴 ID |一个 | 6 |空 |空 |是 | BTREE | | | |日志条目 | 1 |客户 ID | 1 |客户 ID |一个 | 20377 |空 |空 |是 | BTREE | | | +-------------+------------+--------------+-------- --------+--------------+------------+--------------+- ---------+--------+------+------------+---------+- --------------+
编辑 2:在 log_codes 上添加了复合索引:(log_code, category_overview) 和 (log_code, category_overview)。 (customer_id, partner_id) 在 log_entries 上。
以下是一些 EXPLAIN 输出(查询返回 66818 行):
EXPLAIN SELECT log_entries.logentry_id, log_entries.date, log_codes.log_code_desc FROM log_entries
INNER JOIN log_codes ON log_entries.log_code = log_codes.log_code
WHERE log_entries.partner_id = 1 AND log_codes.category_overview = 1 ORDER BY logentry_id DESC
+----+-------------+-------------+--------+---- ---------------------------------+------------+--- ------+----------+--------+---------- ------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+-------------+-------------+--------+------- ------------------+------------+------ ---+----------+--------+-------------- ---------------+ | 1 |简单 |日志条目 |参考 | log_code,partner_id |合作伙伴 ID | 2 |常量 | 156110 |使用哪里;使用文件排序 | | 1 |简单 |日志代码 | eq_ref | PRIMARY,code_overview,overview_code |初级 | 2 | log_entries.log_code | 1 |使用位置 | +----+-------------+-------------+--------+------- ------------------+------------+------ ---+----------+--------+-------------- ---------------+
但我也有一些我认为不会影响索引设计的 LEFT JOIN,但它们会导致“使用临时”问题。这是 EXPLAIN 输出(查询返回 66818 行):
EXPLAIN SELECT log_entries.logentry_id, log_entries.date, log_codes.log_code_desc FROM log_entries
INNER JOIN log_codes ON log_entries.log_code = log_codes.log_code
LEFT JOIN partners ON log_entries.partner_id = partners.partner_id
LEFT JOIN joined_table1 ON log_entries.t1_id = joined_table1.t1_id
LEFT JOIN joined_table2 ON log_entries.t2_id = joined_table2.t2_id
LEFT JOIN joined_table3 ON log_entries.t3_id = joined_table3.t3_id
LEFT JOIN joined_table4 ON joined_table3.t4_id = joined_table4.t4_id
LEFT JOIN joined_table5 ON log_entries.t5_id = joined_table5.t5_id
LEFT JOIN joined_table6 ON log_entries.t6_id = joined_table6.t6_id
WHERE log_entries.partner_id = 1 AND log_codes.category_overview = 1 ORDER BY logentry_id DESC;
+----+-------------+---------------+--------+-- ------------------------------------------------+-------------- -+---------+--------------+------+---- ----------------------------------------------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+-------------+---------------+--------+----- --------------------------------+---------------+- --------+--------------+------+------ ----------------------------------------------------+ | 1 |简单 |日志代码 |参考 | PRIMARY,code_overview,overview_code |概览代码 | 1 |常量 | 54 |使用哪里;使用临时的;使用文件排序 | | 1 |简单 |日志条目 |参考 | log_code,partner_id |日志代码 | 2 | log_codes.log_code | 1811 |使用位置 | | 1 |简单 |合作伙伴 |常量 |初级 |初级 | 2 |常量 | 1 |使用索引 | | 1 |简单 |加入表1 | eq_ref |初级 |初级 | 1 | log_entries.t1_id | 1 |使用索引 | | 1 |简单 |加入表2 | eq_ref |初级 |初级 | 1 | log_entries.t2_id | 1 |使用索引 | | 1 |简单 |加入表3 | eq_ref |初级 |初级 | 3 | log_entries.t3_id | 1 | | | 1 |简单 |加入表4 | eq_ref |初级 |初级 | 3 |加入表3.t4_id | 1 |使用索引 | | 1 |简单 |加入表5 | eq_ref |初级 |初级 | 4 | log_entries.t5_id | 1 |使用索引 | | 1 |简单 |加入表6 | eq_ref |初级 |初级 | 4 | log_entries.t6_id | 1 |使用索引 | +----+-------------+---------------+--------+----- --------------------------------+---------------+- --------+--------------+------+------ ----------------------------------------------------+
不知道这是个好主意还是坏主意,但子查询似乎摆脱了“使用临时”。这是两种常见情况的 EXPLAIN 输出。此查询返回 66818 行:
EXPLAIN SELECT log_entries.logentry_id, log_entries.date, log_codes.log_code_desc FROM log_entries INNER JOIN log_codes ON log_entries.log_code = log_codes.log_code
WHERE log_entries.partner_id = 1
AND log_entries.log_code IN (SELECT log_code FROM log_codes WHERE category_overview = 1) ORDER BY logentry_id DESC;
+----+--------+-------------+------ ------------+--------------------------------------+ ------------+---------+----------+---- --+------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+--------+-------------+--------- --------+-------------------------------------------------+--- ---------+---------+----------+------ -+--------------+ | 1 |初级 |日志条目 |参考 | log_code,partner_id |合作伙伴 ID | 2 |常量 | 156110 |使用哪里;使用文件排序 | | 1 |初级 |日志代码 | eq_ref | PRIMARY,code_overview |初级 | 2 | log_entries.log_code | 1 | | | 2 |依赖子查询 |日志代码 |唯一子查询 | PRIMARY,code_overview,overview_code |初级 | 2 |功能 | 1 |使用位置 | +----+--------+-------------+--------- --------+-------------------------------------------------+--- ---------+---------+----------+------ -+--------------+
以及关于客户的概述,查询返回 12 行:
EXPLAIN SELECT log_entries.logentry_id, log_entries.date, log_codes.log_code_desc FROM log_entries INNER JOIN log_codes ON log_entries.log_code = log_codes.log_code
WHERE log_entries.partner_id = 1 AND log_entries.customer_id = 10000
AND log_entries.log_code IN (SELECT log_code FROM log_codes WHERE category_overview = 1) ORDER BY logentry_id DESC;
+----+--------+-------------+------ -----------+---------------------------------------- ------------+-------------+---------+------------ ----------+------+------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+--------+-------------+--------- --------+----------------------------------------- ---------+--------------+---------+--------------- --------+------+------------------+ | 1 |初级 |日志条目 |参考 | log_code,partner_id,customer_id,customer_partner |客户 ID | 4 |常量 | 27 |使用哪里;使用文件排序 | | 1 |初级 |日志代码 | eq_ref | PRIMARY,code_overview |初级 | 2 | log_entries.log_code | 1 | | | 2 |依赖子查询 |日志代码 |唯一子查询 | PRIMARY,code_overview,overview_code |初级 | 2 |功能 | 1 |使用位置 | +----+--------+-------------+--------- --------+----------------------------------------- ---------+--------------+---------+--------------- --------+------+------------------+
【问题讨论】:
-
复合索引的正确结构取决于基数。如果空间不是问题,那么使用多个索引可能会更好,以最好地服务于这些不同的查询。请在为每个相关字段添加单列索引后发布 SHOW INDEXES 的输出?
-
谢谢!我向相关字段添加了单列索引(感谢@Shiplu)。 SHOW INDEXES 的输出添加到我的问题中。在测试 WHERE category_overview=1 查询时使用 category_overview 索引。但是在 SHOW EXPLAIN 上,我在 log_codes 表上得到“使用 where;使用临时;使用文件排序”,这似乎是一个主要瓶颈。