2014-07-10 45 views
2

我有一位客户要求我调整他的MySQL数据库,以实现一些新功能并提高现有Web应用程序的性能。创建辅助表以提高大型MySQL表的性能?

最大的桌子(〜90 GB)拥有超过200M行,并且以定期间隔(每次访问他拥有的任何一个网站时都会有一次)增长。由于连续的INSERT,从后端页面执行的每个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 from visits_stats where datetime=20140715 and device="ios"获取呢?

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

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

再次感谢。

+1

你为什么不发布查询,表和索引的定义以及执行计划,使这里的人真的可以试着帮你吗? –

回答

4

编辑:我之前说过不使用分区。但是比尔说得对,他所描述的方式会起作用。你唯一担心的是如果你试图在101个分区中进行选择,那么整个事情就会陷入瘫痪。如果你不打算这样做,那么分区将解决问题。首先修复你的索引。

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

现在,你需要修剪你的索引。这是缓慢的主要原因。删除不属于普通SELECT语句的所有内容的索引。根据您的SELECT报表中的WHERE请求添加多列索引。

因此(除了您的主键),您希望datetime, device的索引仅作为多列索引,根据您发布的SELECT声明。

如果更改为TokuDB,插入将会快得多,如果您坚持使用MyISAM,那么您可以通过使用INSERT DELAYED而不是INSERT来加速整个事情。与此唯一的问题是,刀片不会过日子,但是每当MySQL的决定没有太多的负荷将增加。

另外,如果上述仍没有帮助,您的最终选择是使用两个表。一个表,你SELECT从,另一个你INSERT到。一旦大概一天,你就可以将插入表复制到选择表中。尽管这意味着您选择的表格中的数据可能会长达24小时。

以外,你将不得不彻底改变表结构,为此,我不能告诉你怎么做,因为这取决于您使用它到底是什么,或者使用MySQL之外的东西这一点。不过,我上面的优化应该可以工作。

3

我会建议寻找分区。由于MySQL的限制,您必须将datetime添加到主键才能生效。主键或唯一键必须包含用于对表进行分区的列。

同时将datetime上的索引转换为(datetime, device)的复合索引。这将是一个,其中包含您展示的查询的索引,因此查询可以单独从索引获取答案,而无需触摸表格行。

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`, `datetime`), -- compound primary key is necessary in this case 
KEY `datetime` (`datetime`,`device`), -- compound index for the SELECT 
KEY `webmaster_id` (`webmaster_id`), 
KEY `country` (`country`), 
KEY `connection` (`connection`), 
KEY `device` (`device`), 
KEY `provider` (`provider`) 
) ENGINE=InnoDB 
PARTITION BY HASH(datetime) PARTITIONS 101; 

所以,当你查询select count(*) from visits where datetime=20140715 and device='ios',查询只扫描一个分区,在表中的行约1%。然后在该分区内,使用索引进一步缩小范围。

插入也应该改进,因为它们正在更新更小的索引。

我使用一个素数做散列分区时,帮助分区保持更均匀充满的情况下,插入的日期遵循规律。

将90GB表格转换为分区需要很长时间。您可以使用pt-online-schema-change来避免阻止您的应用程序。

,你甚至可以在MySQL 5.6赚更多的分区,如果你愿意,在理论上可达1024在MySQL 5.5和8192。尽管有数千个分区,但您可能遇到不同的瓶颈,例如打开的文件数量。

P.S .: HASH索引不支持MyISAM或InnoDB。 HASH索引仅支持MEMORY和NDB存储引擎。

2

您现在处在被称为大数据查询/大数据处理的问题中。为了处理大数据,很多解决方案可用,但不幸的是,它们都不容易实现。您始终需要一个团队来构建大数据以满足您的需求。我可能在这里定义的一些解决方案如下。 1. Big Table Google使用这种技术创建了一个包含数千列的大型表(为了尽量减少垂直记录)。为此,您必须分析数据,然后根据相似性进行分区,然后用适当的名称标记这些相似性。现在您必须编写查询,这些查询将首先通过某种算法进行分析,以检查哪些列空间需要查询。 没有足够简单 2.分布式数据库横跨多重机 的Hadoop文件系统是一种完全解决存储和查询大数据的问题创造了一个开源的Apache项目。在早期的时候,Space就是问题,系统足够处理小数据,但现在空间不是问题。即使Small组织也有本地存储的tera字节数据。但是这个TB级的数据不能一次性在一台机器上处理。即使是一台巨型机器也需要数天的时间来处理总体运营。这就是为什么hadoop在那里。

如果你是个人,然后肯定你有麻烦了,你需要做这个痛苦的任务,为您的资源。但是,您可以在不使用这些技术的情况下使用这些技术的精髓。
您可以自由尝试这些技巧。只要研究处理大数据的文章。关系数据库查询是不是要去工作,你的情况