mysql查询先慢后快

标签 mysql performance

我有 2 个 myISAM 表,分别称为“tests”和“completed_tests”,一个有 170 个条目,另一个有 118k 个条目。当我运行此查询时:

SELECT ct.archive, ct.status, ct.score, ct.users_LOGIN, t.lessons_ID, t.content_ID, t.keep_best 
 FROM completed_tests ct,tests t 
WHERE ct.status != 'deleted' and ct.status != 'incomplete' and t.id=ct.tests_ID and t.lessons_ID=10;

然后大约需要 30 秒才能完成。对同一查询或相关查询(例如不同的 lessons_ID)的后续调用要快得多。即使我重置查询缓存或重新启动 mysql 服务器,它们仍然更快。我想这意味着表被缓存到内存中(并留在那里)。 我的问题是这个特定的查询似乎在运行这个应用程序的高流量站点上引起了问题(我猜是因为服务器内存很慢并且清空了它的缓存?)。 我的问题是:

  • 有没有办法在我的系统上始终如一地复制 30 英寸的延迟,以便我可以尝试优化查询?例如,我应该清空系统缓存吗?
  • 有没有办法优化上面的查询?运行解释给出:

运行解释给出:

mysql> explain SELECT ct.archive, ct.status, ct.score, ct.users_LOGIN, t.lessons_ID, t.content_ID, t.keep_best FROM completed_tests ct,tests t WHERE ct.status != 'deleted' and ct.status != 'incomplete' and t.id=ct.tests_ID and t.lessons_ID=10;
+----+-------------+-------+------+-----------------+----------+---------+---------------+------+-------------+
| id | select_type | table | type | possible_keys   | key      | key_len | ref           | rows | Extra       |
+----+-------------+-------+------+-----------------+----------+---------+---------------+------+-------------+
|  1 | SIMPLE      | t     | ref  | PRIMARY,idx1    | idx1     | 3       | const         |    4 |             |
|  1 | SIMPLE      | ct    | ref  | tests_ID,status | tests_ID | 3       | firstcho.t.id | 1025 | Using where |
+----+-------------+-------+------+-----------------+----------+---------+---------------+------+-------------+

据我了解,这表明索引已成功使用。 感谢大家。

表结构

>show create table 'tests';
CREATE TABLE `tests` (
  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `active` tinyint(1) NOT NULL DEFAULT '1',
  `content_ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `lessons_ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `name` varchar(255) NOT NULL DEFAULT '',
  `mastery_score` tinyint(4) unsigned NOT NULL DEFAULT '0',
  `description` text,
  `options` text,
  `publish` tinyint(1) DEFAULT '1',
  `keep_best` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `idx1` (`lessons_ID`)
) ENGINE=MyISAM AUTO_INCREMENT=171 DEFAULT CHARSET=utf8

>show create table completed_tests;
CREATE TABLE `completed_tests` (
  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `users_LOGIN` varchar(100) DEFAULT NULL,
  `tests_ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `test` longblob,
  `status` varchar(255) DEFAULT NULL,
  `timestamp` int(10) unsigned NOT NULL DEFAULT '0',
  `archive` tinyint(1) NOT NULL DEFAULT '0',
  `time_start` int(10) unsigned DEFAULT NULL,
  `time_end` int(10) unsigned DEFAULT NULL,
  `time_spent` int(10) unsigned DEFAULT NULL,
  `score` float DEFAULT NULL,
  `pending` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `users_login` (`users_LOGIN`),
  KEY `tests_ID` (`tests_ID`),
  KEY `status` (`status`),
  KEY `timestamp` (`timestamp`),
  KEY `archive` (`archive`),
  KEY `score` (`score`),
  KEY `pending` (`pending`)
) ENGINE=MyISAM AUTO_INCREMENT=117996 DEFAULT CHARSET=utf8

最佳答案

对于高流量站点上运行此程序并遇到问题的其他用户,他们完全有可能遇到您无法控制的数据库配置问题。除此之外,这里有一些有用的建议。

提高性能

以下假设来自 tests:completed_tests 的 1:n 关系基于 t.id:ct.tests_id,其中 completed_tests 中 n 行的测试中总会有一行。

建议使用以下附加索引来帮助连接

CREATE INDEX `ct_to_tests` ON completed_tests (tests_id,status);

此外,如果您能够将 ct.status 更改为 ENUM('deleted','status',..... any other possibilieis ....)(假设有限可用状态的数量,这是完全可行的)那么这也将提高性能,因为它将删除唯一的文本搜索。

我建议 ENUM 的原因很简单。 status 看起来是一个定义为 VARCHAR(255) 的字段,它以编程方式填充,因此将具有有限数量的离散值。如果您能够将 VARCHAR 更改为 ENUM,那么 MySQL 将能够将其视为数字字段。这是因为在幕后,ENUM 中的每个字符串都被赋予了一个数字索引,它是在 ENUM 上匹配时使用的索引,而不是使用时的完整字符串VARCHAR,这样效率更高。

SELECT
    t.lessons_ID, 
    t.content_ID, 
    t.keep_best,
    ct.archive, 
    ct.status, 
    ct.score, 
    ct.users_LOGIN

FROM tests t

INNER JOIN completed_tests ct
    ON ct.status NOT IN ('deleted,'status')
    AND ct.tests_id = t.id

WHERE t.lessons_ID = 10

关于mysql查询先慢后快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9409518/

相关文章:

javascript - 为什么 Javascript `iterator.next()` 返回一个对象?

c - 优化速度 - C 中的 4 维数组查找

python - 从列表中消除半重复项的高性能方法

mysql - 为什么字符集从utf8mb4改为utf8后表的索引存储大小变大?

php - PDO::__construct():服务器发送的字符集 (255) 客户端未知。请向开发人员报告

mysql - 两个 XAMPP WordPress 安装,其中一个指向不同的 URL,但都无法正常工作

java - Access/更新共享数据库

mysql - 从 EC2 服务器上安装的 phpMyAdmin 连接到 RDS 实例

mysql - 通过多个连接加速 SQL 查询

c++ - 我可以在类源文件的单独源文件中定义成员函数吗?