在mysql上运行缓慢的sql
Posted
技术标签:
【中文标题】在mysql上运行缓慢的sql【英文标题】:Slow running sql on mysql 【发布时间】:2011-10-08 03:44:52 【问题描述】:考虑下表及其索引:
CREATE TABLE '交互' ( 'oid' bigint(20) 非空, 'archieved' 日期时间 DEFAULT NULL, '内容' 长文本 COLLATE utf8_bin, 'contentSentiment' int(11) 默认为 NULL, 'createdAt' 日期时间 DEFAULT NULL, 'id' varchar(255) 整理 utf8_bin 默认为 NULL, 'interactionSource' 长文本 COLLATE utf8_bin, '链接' varchar(255) 整理 utf8_bin DEFAULT NULL, 'source' varchar(255) 整理 utf8_bin DEFAULT NULL, 'title' varchar(255) 整理 utf8_bin DEFAULT NULL, '类型' int(11) 默认为空, 'authorKloutScore' int(11) 默认为空, 主键('oid'), KEY 'createdAt' ('createdAt'), KEY 'fullMonitorFeedSearch' ('criteria_oid','createdAt','authorKloutScore','archieved','type') ) ENGINE=MyISAM 默认字符集=utf8 COLLATE=utf8_bin
如果有一个索引 (fullMonitorFeedSearch) 覆盖它,为什么以下查询运行缓慢?顺便说一句,如果删除了 'interactio0_.TYPE = 2',则 sql 将在 0.01 秒内运行。
选择interactio0_.oid FROM 交互interactionio0_ 其中interactio0_.criteria_oid = 21751021 AND interactio0_.createdat = 10 AND interactio0_.archieved 为 NULL AND interactio0_.TYPE = 2 ORDER BY interactio0_.createdat DESC
这是对sql的解释:
+----+-------------+--------------+--------+------- -------------------------------------------------- -----------------+------------------------+-------- -+--------+---------+--------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+-------------+--------------+--------+------- -------------------------------------------------- -----------------+------------------------+-------- -+--------+---------+--------------+ | 1 |简单 |交互0_ |范围 | FKD15475F24AA96F7,createdAt,fullMonitorFeedSearch | fullMonitorFeed 搜索 | 18 |空 | 2323027 |使用位置 | +----+-------------+--------------+--------+------- -------------------------------------------------- -----------------+------------------------+-------- -+--------+---------+--------------+【问题讨论】:
考虑重新排列索引的顺序,将唯一性最小的值放在首位(在您的情况下可能是 TYPE)。 “最不独特”是什么意思? 换句话说,最有可能具有重复值的列。诸如“TYPE”之类的列可能具有非常有限数量的值,而日期时间字段将变化很大。这将在没有大量索引查找的情况下快速减少记录数量。优化器应该做到这一点,但也要考虑重新排列查询本身以匹配。 【参考方案1】:似乎 mysql 可能无法充分使用索引,因为索引中的列与 WHERE 中使用的列不同,而且顺序也不相同。尝试从索引中删除列 authorKloutScore
:
fullMonitorFeedSearch
(criteria_oid
, type
, createdAt
, archieved
)
然后将查询修改为:
SELECT interactio0_.oid
FROM Interaction interactio0_
WHERE interactio0_.criteria_oid = 21751021
AND interactio0_.type = 2
AND interactio0_.createdat = 10
AND interactio0_.archieved IS NULL
ORDER BY interactio0_.createdat DESC;
一些额外的建议/疑虑:
如果type
列应该包含像 1、2、3... 这样的值,我认为将其重新声明为 TINYINT UNSIGNED 是有意义的。这应该允许您存储 0 到 255 范围内的值。
类似的建议是将 authorKloutScore
和 contentSentiment
列重新声明为 TINYINT UNSIGNED 或 SMALLINT UNSIGNED,具体取决于列可能包含的值。
索引和查询提及列criteria_oid
,但表定义中缺少该列。我不确定是错字还是该列不存在。
createdAt
列是 DATETIME,但查询中相应的 WHERE 谓词没有多大意义 - interactio0_.createdat = 10
。它不应该是右侧的日期或日期时间值。还是该列仅用于存储特定数据(日、月或小时)?
查询中的一个特定条件为interactio0_.criteria_oid = 21751021
。正如我上面提到的,表定义中缺少该列。但是,这里的想法是,如果该列是唯一的,则删除所有其他 WHERE 条件更有意义 - 选择 criteria_oid = 21751021
的记录并在 php 中的结果集中进行其他检查。但是,如果该列不是 UNIQUE 并且可能有许多行具有相同的 creative_oid
,那么查询就可以了。
希望以上内容有所帮助!
【讨论】:
【参考方案2】:这可能是基数的问题;如果为 Type 单独创建一个特定的索引会发生什么?
另外,请考虑您的数据场景,更有可能的是 - createdat 将是特定的或归档为 null ?
优化索引时的主要考虑因素之一是考虑数据的常见程度;也就是说,如果您在 4 个字段上建立索引,并且您可以选择一个计数,按这 4 个字段分组,如果您获得大量记录,那么您的索引是错误的。
【讨论】:
以上是关于在mysql上运行缓慢的sql的主要内容,如果未能解决你的问题,请参考以下文章