我面临一些快速增长的表格增加速度的问题(目前4兆行,每天300k插入)。我希望我可以在这里获得一些想法和建议,以改善我的设置,并在不久的将来关闭我的网站之前从我的方框中挤出最后一点。
设置:
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的值每个查询更改的事实。它是一个2D画布,每行代表画布上的一条线。猜猜知道为1场选择的最大范围绝不大于1200(像素)也很重要。 几周前我升级到MySQL 5.5.10并开始使用分区。 'x1%10000'hashw是我第一次进入分区主题并且没有意识到的方法。它已经给了我一个相当快的SELECT速度,但我确信仍然有优化的空间。
哦,在你问之前......我知道我正在使用MyISAM表。我的一个朋友建议使用innoDB,但已经尝试过了,结果是表格大2倍,SELECT性能大幅下降。我不需要任何花哨的交易和东西......我所需要的只是最好的SELECT性能和INSERT的良好性能。
你会改变什么?我可能会以某种方式调整我的索引吗?我的分区设置是否有任何意义?我是否应该增加分区文件的数量?
欢迎所有建议......我还讨论了与朋友本地复制到内存表中的问题,但我确定表格大小会占用我的RAM并且交换框是公平的只是时间问题。丑陋的事情要看。
当您考虑我的问题时,请记住它正在快速且不可预测地增长。如果由于某种原因它在某处传播病毒,我希望每天看到超过1毫升的插入物。
感谢您阅读和思考它。 :)
编辑:请求的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...
EDIT2:请求的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 - 带索引的基准
好的...我已经用不同的索引做了一些基准测试,结果到目前为止还算不错。对于这个基准测试,我选择了一个2000x2000像素的所有行。
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
然后我删除了除主键之外的所有索引 - &gt; 1900ms
为x1添加了一个索引 - &gt; 1800ms
为y1添加了一个索引 - &gt; 1700ms
为x2添加了一个索引 - &gt; 1500毫秒
为y2添加了一个索引 - &gt; 900毫秒!
到目前为止,这是非常令人惊讶的......出于某种原因,我在考虑为x1 / y1和x2 / y2组合索引会以某种方式有意义,但实际上看起来我错了。
EXPLAIN现在返回:
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作为键而不是全部四个?
但是,我仍在寻找更多的想法和建议,特别是有关分区和正确哈希的建议。
答案 0 :(得分:2)
首先,我将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
并确保在该表达式上有一个索引:
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
)
答案 1 :(得分:1)
MyISAM可以使用,只要您不更新行。更新MyISAM表上的行时,MySQL会锁定整个表,阻止任何SELECT和INSERTS执行,直到UPDATE完成。 UPDATE优先于SELECT,所以如果你有很多UPDATE在运行,你的SELECTS会等到它们全部完成后再返回任何行。
如果您没问题,请转到您的服务器配置。你的my.cnf文件是什么样的?您需要优化此文件以最大化可用于索引的内存量。如果这些SELECT速度变慢,那是因为你的表索引不适合内存。如果MySQL无法将表索引放入内存中,那么它必须转到磁盘并执行表扫描以获取数据。这将 kill 表现。
编辑5/18/2011美国东部时间晚上9:30
在查看了my.cnf之后,我注意到您已经零 MyISAM优化了。您的起始位置将是key_buffer_size
变量。根据经验,此变量设置在系统总可用内存的25%到50%之间。你的系统有8GB可用内存,所以大约3GB左右是最低起点,我会说。但是,如果您知道可以控制系统上的其他变量,则可以根据需要估算需要的数量并进行优化。
你应该做的是cd到你的mysql数据目录(通常是/var/lib/mysql
),这是你所有数据文件所在的位置。快速了解您拥有多少索引数据
sudo du -hc `find . -type f -name "*.MYI"
此命令将查看所有MyISAM索引文件的大小,并告诉您它们的总大小。如果你有足够的内存,你想让你的my.cnf BIGGER中的key_buffer_size
大于所有MYI文件的总大小。这将确保您的MyISAM索引在内存中,因此MySQL不必为索引数据访问磁盘。
快速说明,不要随便增加key_buffer_size
willy nilly。这只是MySQL的一个需要内存的区域,还有其他需要平衡内存使用的移动部分。 MySQL连接占用内存,不同的表引擎为其索引使用不同的内存池,MySQL使用其他内存来处理不同的内容。如果因为设置key_buffer_size
太大而内存不足,那么您的服务器可能会开始分页(使用虚拟内存,这会使KILL性能更高)或者更糟糕的是崩溃。如果您不确定,请从较小的值开始,检查您的内存使用情况,并增加它,直到您对性能满意为止,并且您的服务器没有崩溃。
答案 2 :(得分:1)
请记住,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
;
或者您可以像建议的其他回复一样使用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为了满足查询需要考虑多少行。
也许值得一看RTREE指数,虽然我自己也没有和他们一起玩过。
答案 3 :(得分:0)
你得到什么样的速度?由于您不需要任何关系内容,因此您应该考虑将数据移至Redis,它应该可以轻松地在您的计算机上执行+ 100k插入或读取/秒。