mysql - 创建辅助表以提高大型 MySQL 表的性能?

标签 mysql performance indexing

我有一位客户要求我调优他的 MySQL 数据库,以实现一些新功能并提高现有网络应用程序的性能。

最大的表 (~90 GB) 有超过 2 亿行,并且以周期性的间隔增长(每次访问他拥有的任何网站一个)。由于连续插入,从后端页面执行的每个 SELECT 查询都需要一段时间才能完成,因为每次都会重新生成索引。

我在自己的服务器上模拟了从 BTREE 索引到 HASH 索引的切换。 SELECT 和 INSERT 都没有运行得更快。该表使用 MyISAM 作为存储引擎。只有 INSERT 和 SELECT,没有 UPDATE 或 DELETE。

我想出了创建一个辅助表的想法,该辅助表与每个 INSERT 一起更新,以加速来自后端的每个 SELECT 查询。我知道这是不好的做法,但是,我确信统计页面的性能会有所提高。

我不是数据库性能专家,您可能已经注意到了...是否有更好的方法?

顺便说一下,我从 phpMyAdmin 看到表中的大多数索引的基数都为 0。在我的模拟中,这没有发生。我不确定为什么会这样。

非常感谢。

第一次更新:我刚刚了解到哈希索引不适用于 MyISAM 引擎。

第二次更新:好的。这是表架构。

CREATE TABLE `visits` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `datetime` int(8) NOT NULL,
 `webmaster_id` char(18) NOT NULL,
 `country` char(2) NOT NULL,
 `connection` varchar(15) NOT NULL,
 `device` varchar(15) NOT NULL,
 `provider` varchar(100) NOT NULL,
 `ip_address` varchar(15) NOT NULL,
 `url` varchar(300) NOT NULL,
 `user_agent` varchar(300) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `datetime` (`datetime`),
 KEY `webmaster_id` (`webmaster_id`),
 KEY `country` (`country`),
 KEY `connection` (`connection`),
 KEY `device` (`device`),
 KEY `provider` (`provider`)
) ENGINE=InnoDB;

因此,与其执行诸如select count(*) from visits where datetime=20140715 and device="ios" 之类的查询,不如从select count 获取它更好从 visits_stats where datetime=20140715 and device="ios"?

如前所述,INSERT 比 SELECT 频繁得多,但我的客户希望提高用于检索聚合数据的后端的性能。使用我的方法,每次访问都意味着一个 INSERT 和一个 INSERT/UPDATE(或 REPLACE),这将增加一个或多个计数器(我还没有决定 visits_stats 表的模式,上面的查询只是一个例子)。

除此之外,我还决定用外部表中的适当 ID 替换一些字段。到目前为止,数据存储在诸如 connection=cable、device=android 等字符串中。我不确定这会如何影响性能。

再次感谢。

最佳答案

编辑:我之前说过不要使用分区。但比尔是对的,他所描述的方式是可行的。您唯一担心的是,如果您尝试在 101 个分区中进行选择,那么整个事情就会停滞不前。如果您不打算这样做,那么分区就可以解决问题。不过,请先修复您的索引。

您的主要问题是 MyISAM 不是最好的引擎,InnoDB 也不是。 TokuDB 将是您的最佳选择,但您必须将其安装在服务器上。

现在,您需要修剪索引。这是速度慢的主要原因。删除不属于常见 SELECT 语句的所有内容的索引。在 SELECT 语句的 WHERE 中准确请求的内容上添加多列索引。

因此(除了您的主键之外)您希望根据您发布的 SELECT 语句在 datetime, device 上建立一个仅作为多列索引的索引。

如果你改用 TokuDB,插入会快得多,如果你坚持使用 MyISAM,那么你可以通过使用 INSERT DELAYED 而不是 INSERT 来加快整个过程。唯一的问题是插入不会生效,但会在 MySQL 确定没有太多负载时添加。

或者,如果上述方法仍然没有帮助,您最后的选择是使用两个表。您从中SELECT 的一个表,以及您INSERT 到的另一个表。大约一天一次,然后将插入表复制到选择表。尽管这意味着您选择的表中的数据最多可能存在 24 小时。

除此之外,您将不得不完全更改表结构,为此我无法告诉您该怎么做,因为这取决于您使用它的确切目的,或者为此使用 MySQL 以外的其他东西。但是,我的上述优化应该有效。

关于mysql - 创建辅助表以提高大型 MySQL 表的性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24679057/

相关文章:

mysql - 如何根据table1计算table2中的行包括null?

PHP 和 MySQL - 排序或分组 - 在 ID 之后

performance - Scala 中的并发处理

android - 带有 getView() 的 ListView 由于不断的 GC 而过度缓慢?

c# - SQL Server 响应时间不一致

mysql - 优化大型关键字表?

mysql - 计数准确的地方不多或少 mysql

php - 根据数组数据分离出数组

Python Pandas isin 返回索引

postgresql - 从 Postgres 9.1 中的 tsvector 列上的 GIN 索引检索键