优化MySQL索引和查询执行时间

优化MySQL索引和查询执行时间,mysql,sql,query-optimization,Mysql,Sql,Query Optimization,关于MySQL中查询性能的问题。我有一张230万条记录的表格(这是我处理过的最大的一张),而且还在增长。该表是数据库的一部分,用于跟踪用户的登录情况,以及在类似于测验的单独会话中的得分情况。对于手头的查询,我需要所有会话的“highscore表” 因此,为了更好地分析用户的进度,每个问题都会存储会话中的得分。会话结合了用户的总积分,会话连接到用户 首先,查询执行时间接近12秒(不可接受),表和查询数据在“原始集”下如下所示。在“改进的分数表”下,情况有所改变,索引进行了一些优化。这导致查询执行时

关于MySQL中查询性能的问题。我有一张230万条记录的表格(这是我处理过的最大的一张),而且还在增长。该表是数据库的一部分,用于跟踪用户的登录情况,以及在类似于测验的单独会话中的得分情况。对于手头的查询,我需要所有会话的“highscore表”

因此,为了更好地分析用户的进度,每个问题都会存储会话中的得分。会话结合了用户的总积分,会话连接到用户

首先,查询执行时间接近12秒(不可接受),表和查询数据在“原始集”下如下所示。在“改进的分数表”下,情况有所改变,索引进行了一些优化。这导致查询执行时间约为2秒

我的问题是:有没有其他优化方法?正如我所说,230万(正在计算)是我见过的最大的表,所以我在这方面没有那么丰富的经验,优化在几秒钟内就能产生比十分之一秒改进更快的结果

原始设置

CREATE TABLE `players` (
  `id_players` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_organisations` int(10) unsigned NOT NULL,
  `player_name` varchar(45) NOT NULL,
  `player_comments` text NOT NULL,
  PRIMARY KEY (`id_players`),
  KEY `FK_players_organisation` (`id_organisations`),
  CONSTRAINT `FK_players_organisation` FOREIGN KEY (`id_organisations`) REFERENCES `organisations` (`id_organisations`)
) ENGINE=InnoDB AUTO_INCREMENT=9139 DEFAULT CHARSET=latin1

SELECT COUNT(*) FROM players => 9126

CREATE TABLE `scores` (
  `id_scores` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_sessions` int(10) unsigned NOT NULL,
  `id_levels` int(10) unsigned NOT NULL,
  `id_categories` int(10) unsigned NOT NULL,
  `score_points` int(10) unsigned NOT NULL,
  `score_correct` tinyint(4) NOT NULL,
  `score_submitted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id_scores`),
  KEY `FK_scores_sessions` (`id_sessions`),
  KEY `FK_scores_levels` (`id_levels`),
  KEY `FK_scores_categories` (`id_categories`),
  KEY `Index_3_points` (`score_points`),
  KEY `Index_4_submitted` (`score_submitted`)
) ENGINE=InnoDB AUTO_INCREMENT=2328510 DEFAULT CHARSET=latin1

SELECT COUNT(*) FROM scores => 2328469

CREATE TABLE `sessions` (
  `id_sessions` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_players` int(10) unsigned NOT NULL,
  `id_classes` int(11) DEFAULT NULL,
  `session_start` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `session_grade` decimal(4,1) NOT NULL,
  `session_ip` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id_sessions`),
  KEY `FK_sessions_players` (`id_players`),
  KEY `FK_sessions_classes` (`id_classes`)
) ENGINE=InnoDB AUTO_INCREMENT=40800 DEFAULT CHARSET=latin1

SELECT COUNT(*) FROM sessions => 40788
“违规”查询:

SELECT sum( s.score_points ) AS score_points, p.player_name
FROM scores s
INNER JOIN sessions se      ON s.id_sessions      = se.id_sessions
INNER JOIN players p        ON se.id_players      = p.id_players
GROUP BY se.id_sessions
ORDER BY score_points DESC
LIMIT 50;
使用上述分数表进行上述查询大约需要12秒钟。(在解释输出下方)

(使用临时文件和使用文件排序显然臭名昭著)

经过一些“研究”后,我改变了分数表中的索引(索引3分),形成如下表:

改进分数表

CREATE TABLE `scores` (
  `id_scores` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_sessions` int(10) unsigned NOT NULL,
  `id_levels` int(10) unsigned NOT NULL,
  `id_categories` int(10) unsigned NOT NULL,
  `score_points` int(10) unsigned NOT NULL,
  `score_correct` tinyint(4) NOT NULL,
  `score_submitted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id_scores`),
  KEY `FK_scores_sessions` (`id_sessions`),
  KEY `FK_scores_levels` (`id_levels`),
  KEY `FK_scores_categories` (`id_categories`),
  KEY `Index_4_submitted` (`score_submitted`),
  KEY `Index_3_points` (`id_sessions`,`score_points`)
) ENGINE=InnoDB AUTO_INCREMENT=2328510 DEFAULT CHARSET=latin1
使用上面的分数表,查询执行时间下降到大约2秒。解释(如下)并没有真正改变很多(至少,臭名昭著的临时和文件端口仍然在使用)


如果有人知道进一步的优化技巧,我很想听听

前50名的分数大概不会经常变化吧

因此,将查询运行到TopScore表中,并对其进行索引。当用户的分数发生变化时,对照高分表进行检查,只有当用户的分数高于第50分时,才更新TopScore表


我还建议,向经常更新的表中添加大量索引可能会对该表的性能产生不利影响。

嗨,波迪卢斯卡,我必须检查一下,但随着时间的推移,我想前50名的变化越来越少。值得一试,谢谢。至于指数:我知道这种权衡,但临界点在哪里?一些数学数据显示,分数表的更新频率约为每天6000次。这并不是我所期望的,但这不可能是一个瓶颈,不是吗?我想我需要这些指数来衡量高分和其他对结果的看法?临界点在哪里?通过这段字符串的三分之二:)请参阅以下主题(特定于MS SQL,但原则相同)您花了很长时间研究了数据库的评测。看看我是否能在假期里得到一些好的读物。。。
CREATE TABLE `scores` (
  `id_scores` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_sessions` int(10) unsigned NOT NULL,
  `id_levels` int(10) unsigned NOT NULL,
  `id_categories` int(10) unsigned NOT NULL,
  `score_points` int(10) unsigned NOT NULL,
  `score_correct` tinyint(4) NOT NULL,
  `score_submitted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id_scores`),
  KEY `FK_scores_sessions` (`id_sessions`),
  KEY `FK_scores_levels` (`id_levels`),
  KEY `FK_scores_categories` (`id_categories`),
  KEY `Index_4_submitted` (`score_submitted`),
  KEY `Index_3_points` (`id_sessions`,`score_points`)
) ENGINE=InnoDB AUTO_INCREMENT=2328510 DEFAULT CHARSET=latin1
id    select_type   table   type   possible_keys                        key                   key_len   ref                      rows     Extra
'1'   'SIMPLE'      'p'     'ALL'  'PRIMARY'                            NULL                  NULL      NULL                     '9326'  'Using temporary; Using filesort'
'1'   'SIMPLE'      'se'    'ref'  'PRIMARY,FK_sessions_players'        'FK_sessions_players' '4'       'earzsql.p.id_players'   '2'     'Using index'
'1'   'SIMPLE'      's'     'ref'  'FK_scores_sessions,Index_3_points'  'Index_3_points'      '4'       'earzsql.se.id_sessions' '35'    'Using index'