在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 范围内的值。

    类似的建议是将 authorKloutScorecontentSentiment 列重新声明为 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的主要内容,如果未能解决你的问题,请参考以下文章

SQL 语句运行缓慢 - 有啥想法吗?

在 Azure SQL 上运行非常缓慢的外部表上选择

在运行非常缓慢的 SQL 的非常大的表上删除查询

Groovy 中的 sql.rows() 运行缓慢

集群 MySQL 环境中运行缓慢的查询

在 XAMPP 服务器上运行的网页加载非常缓慢