具有索引某些相同列的多个索引的表的mysql索引优化

时间:2010-04-06 23:04:32

标签: mysql indexing

我有一个表格,可存储有关第三方网站上访客会话的一些基本数据。这是它的结构:

id, site_id, unixtime, unixtime_last, ip_address, uid

有四个索引:idsite_id/unixtimesite_id/ip_addresssite_id/uid

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

显然,将site_id存储在3个索引中对于写入速度和存储都是低效的,但我认为没办法,因为我需要能够快速查询给定特定site_id的数据。

有关提高效率的任何想法吗?

除了一些非常基本的东西之外,我真的不了解B树,但是让索引的最左边的列成为方差最小的那个 - 更正确吗?因为我认为site_id是ip_address和uid的索引的第二列,但我认为这会使索引效率降低,因为IP和UID的变化将超过站点ID,因为我们只有大约8000每个数据库服务器的唯一站点,但每天在所有~8,000个站点中有数百万个唯一访问者。

我还考虑过完全从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,但这并不是不关心数据库设计的借口。我希望数据库尽可能高效。

3 个答案:

答案 0 :(得分: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树索引的第二个属性:它们是有序的。 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相同。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

你有什么工作。如果你遇到了瓶颈,你需要找出它的cpu,ram,磁盘和/或网络是否相应调整。过早优化是困难和错误。

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

如果已经在所有查询中使用了这些索引,则翻转索引的顺序没有任何意义。

  

但是将索引的最左列作为方差最小的列更正确 - 正确吗?

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