我有一个庞大的艺术家,专辑和曲目数据库。这些项目中的每一个都可以通过胶合表(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,我的第一个问题是返回的速度。
答案 0 :(得分:3)
如果你想要速度,我建议你看看Solr / Lucene。您可以通过调用Solr并从PHP解析结果来存储数据并进行非常快速的查找。而且作为额外的好处,您也可以获得分面搜索(如果我正确解释,这是您问题的任务2)。缺点当然是您可能有冗余信息(一旦存储在DB中,一次存储在Solr文档存储中)。设置需要一段时间(好吧,你可以从Drupal Solr集成中学到很多东西)。
只需查看Solr的PHP参考文档。
以下是有关如何将Solr与PHP结合使用的文章,以防万一:http://www.ibm.com/developerworks/opensource/library/os-php-apachesolr/。
答案 1 :(得分:2)
您可能应该尝试对数据进行非规范化。您的结构针对插入/更新加载进行了优化,但不适用于查询。当我得到它时,你会有比插入/更新查询更多的选择查询。
例如,您可以执行以下操作:
将您的数据存储在规范化结构中。
像这样创建agregate表
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/
要进行搜索,你可能应该在* _tags列上创建FULLTEXT索引
使用像
这样的sql查询此表select * from aggregate where album_tags MATCH (track_tags) AGAINST ('rock')
每天以增量方式重建此表格。
答案 2 :(得分: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。通过这种方式,您可以将所有数据放在一个表中,但是对于cource,它将使用更多的内存。
接下来 - 您应该考虑使用多个数据库。如果每个数据库只包含部分数据(每次查找都会更快),它将会有更多帮助。决定如何在数据库之间传播数据通常是一项相当艰巨的任务:我建议您对标记长度进行一些统计,查找将获得类似trac /艺术家结果计数的长度范围,并将其硬编码到查找代码中。
对于cource你应该考虑MySql调优(我相信你做到了,但以防万一) - 你的所有表应该驻留在RAM中 - 如果不可能尝试获取SSD光盘,raid等。正确的索引和数据库类型/设置也非常重要(MySql甚至可能在内部统计中显示一些瓶颈)。
这个建议可能听起来很疯狂 - 但有时让PHP做一些MySql可以做的计算是件好事。 MySql数据库更难扩展,而PHP处理服务器可以在几分钟内添加。不同的PHP线程可以在不同的CPU核心上运行 - MySql有问题。您可以通过使用一些高级模块来增加PHP性能(您甚至可以自己编写它们 - 在快速C代码中配置PHP脚本和硬编码瓶颈)。
最后但我认为最重要的是 - 你必须使用某种类型的缓存。我知道这真的很难,但我不认为没有一个非常好的缓存系统有任何大项目。在你的情况下,一些标签肯定会比其他标签更受欢迎,所以它应该大大提高性能。缓存是一种艺术形式 - 取决于您可以在其上花费多少时间以及可以使用多少资源,您可以使99%的请求使用缓存。
使用其他数据库/索引工具可能会对您有所帮助,但您应该始终考虑理论查询速度比较(O(n),O(nlog(n))...)以了解它们是否真的可以帮助您 - 使用此工具有时会给你带来低性能增益(比如常数20%),但它们可能会使你的应用程序设计复杂化,而且大部分时间都不值得。
答案 3 :(得分:1)
根据我的经验,大多数“慢”MySQL数据库没有正确的索引和/或查询。所以我先检查一下:
答案 4 :(得分:0)
你可以尝试的事情:
使用Query Analyzer来探索查询的瓶颈。 (在大多数情况下,潜在的DBS在优化方面做得非常出色)
您的表格结构已经很好地规范化了,但是个人经验告诉我,您可以使用可以避免连接和结构的结构来存档更高的性能级别。 subquerys。对于您的情况,我建议将标签信息存储在一个字段中。 (这需要基础DBS的支持)
到目前为止。
答案 5 :(得分:0)
检查您的指数,以及它们是否正确使用。也许MySQL不能胜任这项任务。 PostgreSQL应该类似于使用,但在复杂情况下具有更好的性能。
在一个完全不同的轨道上,google map-reduce并使用其中一个新的花哨的无SQL数据库来实现非常大的数据集。这可以并行地在多个服务器上进行分布式搜索。