2010-04-06 55 views
5

我有一张表,其中存储有关第三方网站上的访问者会话的一些基本数据。这是它的结构:对具有索引某些相同列的多个索引的表的mysql索引优化

id, site_id, unixtime, unixtime_last, ip_address, uid 

有四个指标:idsite_id/unixtimesite_id/ip_addresssite_id/uid

有许多不同类型的,我们查询此表的方式,和所有的人所特有的SITE_ID。带有unixtime的索引用于显示给定日期或时间范围内的访问者列表。另外两个用于查找来自IP地址或“uid”(为每个访客创建的唯一cookie值)的所有访问,以及确定这是新访问者还是返回访问者。

显然,在3个索引内部存储site_id对于写入速度和存储都是低效的,但我没有办法解决它,因为我需要能够快速查询给定特定site_id的这些数据。

任何想法使这更高效?

除了一些非常基本的东西外,我不太了解B树,但是如果索引最左边的一列是最小方差的那一列更有效 - 对吗?因为我认为将site_id作为ip_address和uid索引的第二列,但我认为这会使索引效率降低,因为IP和UID会比站点ID更大,因为我们只有大约8000每个数据库服务器都有独特的网站,但每天大约有8000个网站的数百万独立访问者。

我也考虑彻底从IP和UID索引中删除site_id,因为同一个访问者转到共享相同数据库服务器的多个站点的几率很小,但是在发生这种情况的情况下,我担心确定这是否是该site_id的新访问者可能会很慢。该查询会是这样的:

select id from sessions where uid = 'value' and site_id = 123 limit 1 

...因此,如果这个来访者以前访问过该网站,那就只需要找到这个SITE_ID一行才停下。这不会超快,但可接受的速度很快。但是,假设我们有一个网站每天可以获得50万个访问者,并且特定的访问者喜欢这个网站,并且每天去那里访问10次。现在他们碰巧第一次碰到同一台数据库服务器上的另一个站点。上述查询可能需要相当长的时间来搜索这个UID的所有潜在数千行,遍布整个磁盘,因为它不会为这个站点ID找到一个。

进行此尽可能高效任何有识之士将不胜感激:)

更新 - 这是与MySQL 5.0中的MyISAM表。我的担忧既有性能又有存储空间。这个表格既读又重写。如果我必须在性能和存储之间做出选择,我最关心的是性能 - 但两者都很重要。

我们在我们服务的所有领域大量使用memcached,但这不是不关心数据库设计的借口。我希望数据库尽可能高效。

+0

存储引擎? mysql版本?你想如何提高这个效率 - 明智的使用磁盘或者性能?你有没有解决实际问题,或者这只是一个修辞问题? – ggiroux 2010-04-07 00:39:26

+0

mysql 5.0,myisam引擎。我既关心存储空间又关注性能,因为这既是一个读写表,也是一个重写表。是的,实际的问题。 :) – Sean 2010-04-07 00:46:47

+0

你读过高性能MySQL吗? – 2010-05-07 11:37:22

回答

0

首先,如果使用ip作为字符串而不是将其更改为INT UNSIGNED列,并使用INET_ATON(expr)和INET_NTOA(expr)函数来处理此问题。对整数值建立索引比对可变长度的字符串建立索引更有效。

+0

所有的字段当然是整数... – Sean 2010-04-07 19:03:06

+0

请确保与IPv6不兼容。 2000年,我们来了! – derobert 2010-05-08 03:22:17

0

井指数交易存储性能。它很难,如果你想要两个。如果不知道您运行的所有查询以及每个间隔的数量,就很难进一步优化它。

你有什么工作。如果你遇到瓶颈,你需要找出它的CPU,RAM,磁盘和/或网络,并相应地进行调整。其过早优化的难点和错误。

如果你有任何更新,你可能想切换到innodb,其他明智的myisam适合插入/选择。此外,由于您的行大小很小,您可以查看mysql群集(nbd)。还有一个归档引擎可以帮助满足存储需求,但在5.1中进行分区可能是更好的选择。

翻转索引的顺序没有任何意义,如果这些索引已用于所有查询。

但是将索​​引的最左边一列作为最小方差的那一列更有效率 - 正确吗?

不知道,但我没有听说过这个。这个应用程序对我来说似乎不正确。索引顺序对于排序很重要,并且通过具有多个唯一的第1个最多索引字段,允许更多可能的查询使用索引。

4
除了一些非常基本的东西外,我不太了解B树,但是将索引的最左边一列作为最小方差的那一列更有效 - 对吗?

有你需要知道的B树索引中的一个重要特性:它是可能的(有效的)来搜索全键的任意前缀,但不是后缀。如果您有索引site_ip(site_id, ip),并且您要求where ip = 1.2.3.4,MySQL将不会使用site_ip索引。如果您改为ip_site(ip, site_id),那么MySQL将能够使用ip_site索引。

这是B-tree索引的第二个属性,您应该注意它们:它们是排序的。 b树索引可用于像where site_id < 40这样的查询。

还有一个重要的磁盘驱动器属性要记住:顺序读取便宜,寻找不是。如果有任何不在索引中的列,MySQL必须从表数据中读取该行。这通常是一种寻求,而且缓慢。因此,如果MySQL相信它会像这样读取一小部分表格,它会忽略索引。一次大表扫描(顺序读取)通常比随机读取甚至表中几个百分比的行更快。

顺便说一句,同样适用于寻找索引。在B树中查找关键字实际上可能需要一些搜索,因此您会发现WHERE site_id > 800 AND ip = '1.2.3.4'可能不会使用site_ip索引,因为每个site_id都需要多个索引查找来查找该网站的1.2.3.4记录的开头。但是,将使用ip_site索引。

最终,您将不得不自由使用基准测试,并使用EXPLAIN来找出数据库的最佳索引。请记住,您可以根据需要自由添加和删除索引。非唯一索引不是数据模型的一部分;他们只是一个优化。 PS:基准测试InnoDB,它通常具有更好的并发性能。与PostgreSQL相同。