0

我有三张桌子。一个包含帖子 ( postadata),一个包含标签 ( tag) 和一个链接表 ( tag_data) 我正在运行查询以使用以下查询连接所有帖子及其标签。

    SELECT 
        postdata.data_id as data_id, 
        GROUP_CONCAT(DISTINCT(tag.tag_id)) as tag_ids, 
        GROUP_CONCAT(DISTINCT(tag.tag) ORDER BY tag.tag ASC) as tags
    FROM postdata
    LEFT JOIN tag_data as tag_data
            INNER JOIN tag as tag
                ON tag_data.tag_id = tag.tag_id
    ON postdata.data_id = tag_Data.data_id
    GROUP BY postdata.data_id
    LIMIT 1000

但它非常非常慢。(大约 20 秒)。下面是解释,我似乎找不到问题

1   SIMPLE  postdata    index   NULL    source_id   4   NULL            158808  Using index; Using temporary; Using filesort
1   SIMPLE  tag_data    index   PRIMARY PRIMARY     8   NULL            45279   Using index
1   SIMPLE  tag         eq_ref  PRIMARY PRIMARY     4   tag_data.tag_id 1   

以下是postdata索引

postdata    0   PRIMARY     1   data_id     A   120405  NULL    NULL        BTREE       
postdata    1   source_id   1   source_id   A   168     NULL    NULL        BTREE   

是不是查询有问题?有没有办法更有效地编写它?还是缺少索引?

更新:根据 jordeu 的评论添加索引信息

显示来自 [database_name] 的表状态,其中 Name='postdata'

Name        Engine  Version Row_format  Rows    Avg_row_length  Data_length Max_data_length Index_length    Data_free   Auto_increment  Create_time Update_time Check_time  Collation   Checksum    Create_options  Comment
postdata    InnoDB  10      Compact     158645  43              6832128     0               8421376         4194304     NULL            2012-03-08 09:22:40 NULL    NULL    utf8_unicode_ci NULL

显示像“key_buffer_size”这样的变量

key_buffer_size 16777216
4

4 回答 4

1

在 LEFT JOIN 之后不需要使用 INNER JOIN。

试试这个方法:

SELECT 
    postdata.data_id as data_id, 
    GROUP_CONCAT(DISTINCT(tag.tag_id)) as tag_ids, 
    GROUP_CONCAT(DISTINCT(tag.tag) ORDER BY tag.tag ASC) as tags
FROM postdata
    LEFT JOIN tag_data as tag_data
      ON postdata.data_id = tag_Data.data_id
    LEFT JOIN tag as tag
      ON tag_data.tag_id = tag.tag_id
GROUP BY postdata.data_id
LIMIT 1000
于 2012-04-13T13:08:37.937 回答
1

问题可能是您的索引不适合内存,这会减慢 MySQL 的速度。

例如将“key_buffer_size”增加到 160Mb:

SET GLOBAL key_buffer_size = 167772160

如果您使用 InnoDB,您可能还需要增加“innodb_buffer_size”。

于 2012-04-13T13:43:10.010 回答
0

如果正如评论的那样, DISTINCT 是邪恶的,您可以DISTINCT像这样删除并使其独一无二:

$arr_tag_ids = array_unique(implode(',', $row->tag_ids));
$arr_tags = array_unique(implode(',', $row->tags));
于 2012-04-13T12:59:46.443 回答
0

从您的解释看来,您第一次加入时没有使用任何索引。这可能是因为您有两个 JOIN 和两个 ON 条件。我从未见过像这样格式化的 JOIN。尝试像这样更改

SELECT 
    postdata.data_id as data_id, 
    GROUP_CONCAT(DISTINCT(tag.tag_id)) as tag_ids, 
    GROUP_CONCAT(DISTINCT(tag.tag) ORDER BY tag.tag ASC) as tags
FROM postdata
    LEFT JOIN tag_data as tag_data
      ON postdata.data_id = tag_Data.data_id
    LEFT JOIN tag as tag
      ON tag_data.tag_id = tag.tag_id
GROUP BY postdata.data_id
LIMIT 1000

然后重新运行 EXPLAIN 并查看它是否有所作为。另外,第一次 JOIN 肯定需要 LEFT JOIN 吗?如果可能的话,将其更改为 INNER JOIN 可能会有所帮助。

于 2012-04-13T13:04:54.910 回答