高性能多层标签过滤

Chr*_*ker 10 php sql performance join large-data

我有一个庞大的艺术家,专辑和曲目数据库.这些项目中的每一个都可以通过胶合表(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)                | 
Run Code Online (Sandbox Code Playgroud)

编辑我正在使用PHP,我不反对在脚本中进行任何排序或其他hijinx,我的#1关注点是返回速度.

And*_*lov 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/
Run Code Online (Sandbox Code Playgroud)

为了加快搜索速度,您可能应该在 *_tags 列上创建 FULLTEXT 索引

使用 sql 查询该表,例如

select * from aggregate where album_tags  MATCH (track_tags) AGAINST ('rock')
Run Code Online (Sandbox Code Playgroud)

每天增量重建该表一次。