MYSQL:需要帮助快速增长的表和减less速度(4mio行)

我正在以快速增长的速度增长的桌面(目前有4百万行,每天插入30万行)面临一些问题。 我希望我能在这里得到一些想法和build议,以改善我的设置,挤出我的盒子里的最后一点,在不久的将来把我的网站拿下来之前。

设置:

Intel i7 720 8GB RAM 2x750GB SATA RAID 0 CentOS MySQL 5.5.10 Node.js + node-lib_mysql-client 

表格定义:

 CREATE TABLE IF NOT EXISTS `canvas` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `x1` int(11) NOT NULL, `y1` int(11) NOT NULL, `x2` int(11) NOT NULL, `y2` int(11) NOT NULL, `c` int(4) unsigned NOT NULL, `s` int(3) unsigned NOT NULL, `m` bigint(20) unsigned NOT NULL, `r` varchar(32) NOT NULL, PRIMARY KEY (`id`,`x1`,`y1`) KEY_BLOCK_SIZE=1024, KEY `x1` (`x1`,`y1`) KEY_BLOCK_SIZE=1024, KEY `x2` (`x2`,`y2`) KEY_BLOCK_SIZE=1024 ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=4 /*!50100 PARTITION BY HASH ( ( ( x1 MOD 10000 ) ) + y1 MOD 10000) PARTITIONS 10 */ AUTO_INCREMENT=13168904 ; 

查询:

 SELECT x1,y1,x2,y2,s,c,r,m FROM canvas WHERE 1 AND (( x1 >= 0 AND x1 <= 400 AND y1 >= 0 AND y1 <= 400 ) OR ( x2 >= 0 AND x2 <= 400 AND y2 >= 0 AND y2 <= 400 ) ) ORDER BY id desc 

这是我正在执行的唯一查询,除了x1,y1,x2和y2的值每个查询更改之外。 这是一个2Dcanvas,每一行代表canvas上的一条线。 猜猜知道为1场select的最大范围永远不会大于1200(像素)也很重要。 几个星期前,我升级到MySQL 5.5.10,并开始使用分区。 “x1%10000”hashw是我第一个没有意识到进入分区主题的方法。 它已经给了我一个体面的提高select速度,但我相信还有优化的余地。

哦,在你问之前…我知道我正在使用MyISAM表。 我的一个朋友build议innoDB,但已经尝试过了,结果是2倍大的表和SELECT性能的大幅下降。 我不需要花哨的交易和东西….所有我需要的是最好的SELECT性能和INSERTs体面的performance。

你会改变什么? 我可以以某种方式调整我的索引吗? 我的分区设置是否有意义? 我应该增加分区文件的数量吗?

所有的build议,欢迎…我还讨论过一个本地复制到一个内存表与朋友,但我敢肯定,这只是一个时间的问题,直到表格大小将我的内存和交换框是一个相当丑陋的东西看到。

当你想到我的问题时,请记住它正在迅速增长,难以预料。 如果出于某种原因某处出现病毒,我预计每天会看到超过100万个INSERTS。

感谢您阅读和思考。 🙂

编辑:请求的EXPLAIN结果

 select_type table type possible_keys key key_len ref rows Extra SIMPLE canvas index_merge x1,x2 x1,x2 8,8 NULL 133532 Using sort_union(x1,x2); Using where; Using fileso... 

编辑2:请求my.cnf

 [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 innodb_buffer_pool_size = 1G sort_buffer_size = 4M read_buffer_size = 1M read_rnd_buffer_size = 16M innodb_file_format = Barracuda query_cache_type = 1 query_cache_size = 100M # http://dev.mysql.com/doc/refman/5.5/en/performance-schema.html ;performance_schema [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid 

innoDB值是我的innoDB尝试…猜猜他们不再是必要的。 该服务器也运行其他4个网站,但它们相当小,不值得一提。 无论如何,我要把这个项目搬到一个专门的盒子里。 你的想法可以是激进的 – 我不介意实验。

EDIT3 – 与索引的基准

好吧,大家好我已经用不同的索引做了一些基准testing,结果非常好。 对于这个基准,我select了2000×2000像素的框中的所有行。

 SELECT SQL_NO_CACHE x1,y1,x2,y2,s,c FROM canvas_test WHERE 1 AND (( x1 BETWEEN -6728 AND -4328 AND y1 BETWEEN -6040 AND -4440 ) OR ( x2 BETWEEN -6728 AND -4328 AND y2 BETWEEN -6040 AND -4440 ) ) ORDER BY id asc 

使用我在avarage查询时间之上发布的表/索引定义是: 1740ms

然后我删除了所有索引,除了主键 – > 1900毫秒

增加一个索引x1 – > 1800ms

为y1 – > 1700ms添加了一个索引

增加了一个索引x2 – > 1500ms

增加了一个索引y2 – > 900ms!

到目前为止,这是相当惊人的…出于某种原因,我正在考虑为x1 / y1组合索引,x2 / y2会有所帮助,但实际上看起来我错了。

现在解释返回这个:

 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE canvas_test index_merge x1,y1,x2,y2 y1,y2 4,4 NULL 263998 Using sort_union(y1,y2); Using where; Using fileso.. 

现在我想知道为什么它使用y1 / y2作为键而不是全部四个?

不过,我仍然在寻找更多的想法和build议,特别是关于分区和正确的哈希。

  1. 你的服务器目前使用多less内存?
  2. 这是服务器上唯一的数据库/表吗?
  3. 你是否只使用MyISAM?

MyISAM可以使用,只要你不更新你的行。 当您更新MyISAM表上的一行时,MySQL会locking整个表,阻止任何SELECT和INSERTS执行,直到UPDATE完成。 UPDATE优先于SELECT,所以如果你有很多UPDATE正在运行,你的SELECTS将会等到它们全部完成,然后返回任何行。

如果这样可以,那么转到你的服务器configuration。 你的my.cnf文件是什么样的? 你会想优化这个文件,以最大限度地使用索引的内存量。 如果这些SELECT变慢,这是因为你的表索引不适合内存。 如果MySQL不能将你的表索引放入内存,那么它必须去磁盘并进行表扫描来获取你的数据。 这会杀死性能。

编辑5/18/2011 9:30 PM EST

看完你的my.cnf之后,我注意到你已经没有 MyISAM优化了。 你的起始位置将是key_buffer_sizevariables。 根据经验,这个variables设置为系统总可用内存的25%到50%之间。 你的系统有8GB的内存,所以大概3GB左右是最低的起点。 但是,如果您知道您可以控制系统上的其他variables,则可以根据需要估计需要多less和优化它。

你应该做的是cd到你的mysql数据目录(通常是/var/lib/mysql ),这是你所有的数据文件所在的位置。 一个快速的方法来告诉你有多less索引数据是做的

  sudo du -hc `find . -type f -name "*.MYI" 

这个命令将查看所有MyISAM索引文件的大​​小,并告诉你它们的总大小。 如果你有足够的内存,你希望在my.cnf BIGGER中使你的key_buffer_size大于你所有MYI文件的总大小。 这将确保你的MyISAM索引在内存中,所以MySQL不必为索引数据命中磁盘。

一个简单的说明,不要增加你的key_buffer_size威利。 这只是MySQL需要内存的一个领域,还有其他一些需要平衡内存使用的移动部分。 MySQL连接占用内存,不同的表引擎为其索引使用不同的内存池,而MySQL使用其他内存位来处理不同的事情。 如果因为将key_buffer_size设置得太大而导致内存不足,则服务器可能会启动分页(使用虚拟内存,这将导致KILL性能甚至更高),甚至更糟。 如果您不确定,请从较小的值开始,检查您的内存使用情况,然后增加它,直到您对性能满意为止,并且服务器不会崩溃。

首先,我将SELECT修改为

 SELECT x1,y1,x2,y2,s,c,r,m FROM canvas WHERE x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400 OR x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400 ORDER BY id desc 

而且一定要有一个expression式的索引:

 CREATE INDEX canvas400 ON canvas( x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400 OR x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400 ) 

请记住,MySQL只会为每个查询的每个表使用一个索引。 您的SELECT查询将无法在同一个查询中使用这两个索引 – 它将使用其中一个。 您可能会发现将UNION两个SELECT查询合并在一起可以更有效,这样每个查询都可以使用适当的索引,例如:

 SELECT x1,y1,x2,y2,s,c,r,m FROM canvas WHERE x1 >= 0 AND x1 <= 400 AND y1 >= 0 AND y1 <= 400 UNION SELECT x1,y1,x2,y2,s,c,r,m FROM canvas WHERE x2 >= 0 AND x2 <= 400 AND y2 >= 0 AND y2 <= 400 ; 

或者您可以像build议的其他回复之一一样使用BETWEEN,例如:

 SELECT x1,y1,x2,y2,s,c,r,m FROM canvas WHERE x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400 UNION SELECT x1,y1,x2,y2,s,c,r,m FROM canvas WHERE x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400 ; 

我已经使用了一个UNION,所以我不确定你在哪里放置ORDER BY子句,但是你可以尝试一下。

作为提到的其他回复之一,使用EXPLAIN来查看MySQL将不得不考虑多less行以满足查询。

也许值得一看的是RTREE指数,尽pipe我自己也没有玩过。

你得到什么样的速度? 由于您不需要任何关系性的东西,您应该考虑将您的数据移动到Redis ,它应该很容易地在您的机器上执行+ 100k插入或读取/秒。