2011-08-05 40 views
10

我有一个艺术家,专辑和曲目的大型数据库。这些项目中的每一个都可能有一个或多个通过胶粘表(track_attributes,album_attributes,artist_attributes)分配的标签。有几千(甚至几十万)个标签适用于每种商品类型。高性能多层标签过滤

我试图完成两项任务,而且我很难让查询执行可接受的操作。

任务1)获取有任何给定的标签(如果有艺术家在专辑有任何给定的标签(如果提供的所有音轨))与任何给定的标签(如果有的话)。任何一组的标签可以不存在(即仅一个轨道标记是有效的,没有艺术家或唱片标签)

变异:结果也可呈现由艺术家或按专辑,而不是由轨道

任务2)获取应用于前一个过滤器结果的标签列表,以及每个给定标签有多少个轨道的计数。

我所追求的是方法中的一些一般指导。我尝试了临时表,内部连接,IN(),到目前为止,我所做的所有努力都会导致响应缓慢。我之后的结果的一个很好的例子可以在这里看到:http://www.yachtworld.com/core/listing/advancedSearch.jsp,除了他们只有一层标签,我正在处理三个。

表结构:

Table: attribute_tag_groups 
    Column |   Type    | 
------------+-----------------------------+ 
id   | integer      | 
name  | character varying(255)  | 
type  | enum (track, album, artist) | 

Table: attribute_tags 
    Column      |   Type    | 
--------------------------------+-----------------------------+ 
id        | integer      | 
attribute_tag_group_id   | integer      | 
name       | character varying(255)  | 

Table: track_attribute_tags 
    Column |   Type    | 
------------+-----------------------------+ 
track_id | integer      | 
tag_id  | integer      | 

Table: artist_attribute_tags 
    Column |   Type    | 
------------+-----------------------------+ 
artist_id | integer      | 
tag_id  | integer      | 

Table: album_attribute_tags 
    Column |   Type    | 
------------+-----------------------------+ 
album_id | integer      | 
tag_id  | integer      | 

Table: artists 
    Column |   Type    | 
------------+-----------------------------+ 
id   | integer      | 
name  | varchar(350)    | 

Table: albums 
    Column |   Type    | 
------------+-----------------------------+ 
id   | integer      | 
artist_id | integer      | 
name  | varchar(300)    | 

Table: tracks 
    Column |   Type    | 
-------------+-----------------------------+ 
id   | integer      | 
artist_id | integer      | 
album_id | integer      | 
compilation | boolean      | 
name  | varchar(300)    | 

编辑我使用PHP,我不是反对这样做脚本任何排序或其他hijinx,我的#1关心的是回报的速度。

+2

为什么不包含全部* show create table * s和您当前的查询供我们使用? –

+0

MySQL或PostgreSQL?如果前者如果存在使用后者的良好解决方案,则可能转而使用后者? –

+0

@Denis - MySQL。切换到DBMS不是此时的选项。 –

回答

2

您可能应该尝试对数据进行非规格化。您的结构针对插入/更新加载进行了优化,但不适用于查询。就我所知,你的选择查询比插入/更新查询要多得多。

例如,你可以做这样的事情:

店您在规范化结构的数据。

创建这样

track_id, artist_tags, album_tags, track_tags 
    1 , jazz/pop/, jazz/rock, /heavy-metal/ 

    or 

    track_id, artist_tags, album_tags, track_tags 
    1 , 1/2/, 1/3, 4/ 

agregate表spead了搜索你* _tags列

查询该表与SQL像

select * from aggregate where album_tags MATCH (track_tags) AGAINST ('rock') 

重建这个表大概应该创建FULLTEXT索引每天增量一次。

+0

我现在正在使用此功能来查看性能。感谢您的想法! –

+0

...和?结果是什么? –

+0

仍然建设表和测试。我不会消失:D –

3

如果你想要速度,我建议你看看Solr/Lucene。您可以通过调用Solr并解析PHP的结果来存储数据并进行快速查找。作为一个额外的好处,你也可以进行分面搜索(如果我正确解释,这是你问题的任务2)。缺点是你可能有冗余信息(一旦存储在数据库中,一次存储在Solr文档存储中)。而且它需要一段时间才能设置(好吧,你可以从Drupal Solr集成中学到很多东西)。

请查阅Solr的PHP参考文档。

下面是关于如何在PHP中使用Solr的文章,以防万一:http://www.ibm.com/developerworks/opensource/library/os-php-apachesolr/

+0

我从来没有听说过这个,不知道它是什么。我会在自己的时间研究它,但是我知道,从我浏览的内容中可以看出,我的组织没有财务或时间预算在这个切线上走下坡路 - 我们已经接近这个项目的结束,并且我们已经解决了数据库复制和一个新的Web服务器只是为了到达这里!感谢您的输入! –

+0

我刚刚添加了一篇有用的文章,它只是显示基础知识。 Solr功能非常强大,而且速度非常快。但是,索引您输入的信息可能需要一段时间。 – wimvds

+0

我觉得Lucene现在也是用于标签的。 – JNK

0

事情你可以给一个尝试:

  • 使用Query Analyzer探索你querys的瓶颈。 (在大多数时间底层DBS是相当在做优化了了不起的工作)

  • 你的表结构以及正规化,但个人经验表明我,你可以用结构,使您能够避免归档更大的性能水平加入& subquerys 。对于你的情况,我建议将标签信息存储在一个字段中。 (这需要潜在的DBS支持)

到目前为止。

2

我认为答案很大程度上取决于您希望在项目上花多少钱 - 有些任务甚至在理论上无法完成,例如只能使用一台弱服务器。我会假设你已经准备好升级你的系统。

首先 - 你的表结构强制JOIN的 - 我认为你应该在编写高性能应用程序时尽可能避免它们。我不知道“attribute_tag_groups”是什么,所以我提出了一个表结构:tag(varchar 255),id(int),id_type(enum(track,album,artist))。 Id可以是artist_id,track_id或album_id,具体取决于id_type。这样你就可以将所有的数据放在一张表中,但是它会使用更多的内存。

接下来 - 你应该考虑使用几个数据库。如果每个数据库只包含部分数据(每次查找速度更快),它将有更多帮助。决定如何在数据库之间传播数据通常是相当困难的任务:我建议您对标记长度进行一些统计,找到将获得类似trac/artists结果数的长度范围,并将其硬编码到查找代码中。

你应该考虑使用MySql调整(我确信你这样做了,但以防万一) - 所有表应该驻留在RAM中 - 如果不可能尝试获取SSD盘,RAID等等。适当的索引和数据库类型/设置也非常重要(MySql甚至可能在内部统计中显示一些瓶颈)。

这个建议可能听起来很疯狂 - 但有时候让PHP做一些MySql自己可以做的计算是很好的。 MySql数据库比较难以扩展,而用于PHP处理的服务器可以在几分钟内添加进来。不同的PHP线程可以在不同的CPU内核上运行 - MySql有问题。您可以通过使用一些高级模块来增加您的PHP性能(您甚至可以自己编写它们 - 在快速C代码中分析您的PHP脚本和硬代码瓶颈)。

最后但我认为最重要的 - 你必须使用某种类型的缓存。我知道这确实很难,但我认为没有一个非常好的缓存系统就没有任何大项目。在你的情况下,一些标签肯定会比其他标签更受欢迎,所以它应该大大提高性能。缓存是一种艺术形式 - 取决于您可以花多少时间在它上面以及有多少资源可用,您可以使所有请求中的99%使用缓存。

使用其他数据库/索引工具可能对您有所帮助,但您应该始终考虑理论查询速度比较(O(n),O(nlog(n))...)以了解它们是否真的可以帮助您 - 使用这种工具有时会给你带来低性能增益(比如常量20%),但它们可能会使你的应用程序设计复杂化,而且大部分时间不值得。

1

从我的经验来看,大多数“缓慢”的MySQL数据库没有正确的索引和/或查询。所以我会先检查一下:

  1. 确保所有数据talbes的id字段都是主索引。以防万一。
  2. 对于所有数据表,在外部id字段上创建索引,然后在id上创建索引,以便MySQL可以在搜索中使用它。
  3. 对于您的胶水表,请在两个字段上设置主键,首先是主题,然后是标签。这是为了正常浏览。然后在标签ID上创建一个正常的索引。这是为了搜索。
  4. 还是慢?你在使用MyISAM表格吗?它专为快速查询而设计。
  5. 如果仍然很慢,请对缓慢的查询运行EXPLAIN并将问题中的查询和结果都发布。最好使用完整数据库结构的可导入sql转储。
0

检查您的指数,以及它们是否正确使用。也许MySQL不能胜任这项任务。 PostgreSQL应该类似于使用,但在复杂的情况下具有更好的性能。

在一个完全不同的轨道上,谷歌地图 - 减少和使用这些新的花哨的非SQL数据库之一真的非常大的数据集。这可以并行地在多个服务器上进行分布式搜索。

+0

像MongoDB这样的东西会很好地工作。 – wulfgarpro