Mysql 在类别中搜索时如何优化联接

Mysql 在类别中搜索时如何优化联接,mysql,categories,Mysql,Categories,我有一张桌子,上面有一些物品: CREATE TABLE `ost_content` ( `uid` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `type` enum('media','serial','season','series') NOT NULL, `alias` varchar(200) NOT NULL, `views` mediumint(7) NOT NULL DEFAULT '0', `ratings_c

我有一张桌子,上面有一些物品:

CREATE TABLE `ost_content` (
  `uid` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `type` enum('media','serial','season','series') NOT NULL,
  `alias` varchar(200) NOT NULL,
  `views` mediumint(7) NOT NULL DEFAULT '0',
  `ratings_count` enum('0','1','2','4','5') NOT NULL DEFAULT '0',
  `ratings_sum` mediumint(5) NOT NULL DEFAULT '0',
  `upload_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `conversion_status` enum('converting','error','success','announcement') NOT NULL DEFAULT 'converting',
  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`uid`,`type`),
  KEY `idx_type` (`type`),
  KEY `idx_upload_date DESC` (`upload_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
和表,用于连接具有类别的项目:

CREATE TABLE `ost_categories2media` (
  `categories2media_id` mediumint(6) unsigned NOT NULL AUTO_INCREMENT,
  `categories2media_category_id` smallint(5) unsigned NOT NULL,
  `categories2media_uid` mediumint(8) unsigned NOT NULL,
  PRIMARY KEY (`categories2media_id`),
  KEY `categories2media_media_id` (`categories2media_uid`),
  KEY `categories2media_category_id` (`categories2media_category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=501114 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
然后,我执行查询:

SELECT
    c1.uid,
    c1.alias,
    c1.type,
    c1.views,
    c1.upload_date,
    c1.ratings_sum,
    c1.ratings_count,
    c1.conversion_status
FROM
    ost_content c1
LEFT JOIN ost_categories2media c2m ON c2m.categories2media_uid = c1.uid
WHERE
    c2m.categories2media_category_id = '53'
AND c1.conversion_status IN ('success', 'announcement')
AND c1.type IN ('serial', 'media')
ORDER BY
    c1.upload_date DESC
LIMIT 16, 16
它执行速度慢,分类2媒体分类id检查多行:

+----+-------------+-------+--------+--------------------------------------------------------+------------------------------+---------+---------------------------------+-------+----------------------------------------------+
| id | select_type | table | type   | possible_keys                                          | key                          | key_len | ref                             | rows  | Extra                                        |
+----+-------------+-------+--------+--------------------------------------------------------+------------------------------+---------+---------------------------------+-------+----------------------------------------------+
|  1 | SIMPLE      | c2m   | ref    | categories2media_media_id,categories2media_category_id | categories2media_category_id | 2       | const                           | 32076 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | c1    | eq_ref | PRIMARY,idx_uid_type,idx_type                          | PRIMARY                      | 3       | uakino.c2m.categories2media_uid |     1 | Using where                                  |
+----+-------------+-------+--------+--------------------------------------------------------+------------------------------+---------+---------------------------------+-------+----------------------------------------------+

如何优化或重写此查询?

Mysql索引就像厨师一样,太多的索引不是很有用,因为Mysql每个表只使用一个索引。让我们看一下ost_Categories2媒体, 这是三列上的三个独立索引。您最好使用这样的两个索引

  PRIMARY KEY (`categories2media_id`),
  KEY `categories2media_media_id` (`categories2media_uid`,`categories2media_category_id`)
现在,mysql不再需要在
categories2media\u uid
categories2media\u category\u id
上的索引之间做出选择,它有一个涵盖这两个方面的索引

查看您的ost_内容表,我们看到

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`uid`,`type`),
  KEY `idx_type` (`type`),
  KEY `idx_upload_date DESC` (`upload_date`)
有些索引有点多余。在
uid
字段上筛选的任何查询都可以使用PK,而在
type
上筛选的任何查询都可以使用
idx\u type
,这意味着
idx\u uid\u type
仅用于强制唯一性。但我们可以这样使它更有用:

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`type`,`uid`),
  KEY `idx_upload_date DESC` (`upload_date`)
我们去掉了一个索引!这应该会让你的索引速度更快。您仍然有一个关于上载日期的索引,该索引未在这个特殊查询中使用。那么,综合指数呢

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`type`,`uid`),
  KEY `idx_upload_date DESC` (`uid`,`upload_date`)

Mysql索引就像厨师,太多的索引不是很有用,因为Mysql每个表只使用一个索引。让我们看一下ost_Categories2媒体, 这是三列上的三个独立索引。您最好使用这样的两个索引

  PRIMARY KEY (`categories2media_id`),
  KEY `categories2media_media_id` (`categories2media_uid`,`categories2media_category_id`)
现在,mysql不再需要在
categories2media\u uid
categories2media\u category\u id
上的索引之间做出选择,它有一个涵盖这两个方面的索引

查看您的ost_内容表,我们看到

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`uid`,`type`),
  KEY `idx_type` (`type`),
  KEY `idx_upload_date DESC` (`upload_date`)
有些索引有点多余。在
uid
字段上筛选的任何查询都可以使用PK,而在
type
上筛选的任何查询都可以使用
idx\u type
,这意味着
idx\u uid\u type
仅用于强制唯一性。但我们可以这样使它更有用:

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`type`,`uid`),
  KEY `idx_upload_date DESC` (`upload_date`)
我们去掉了一个索引!这应该会让你的索引速度更快。您仍然有一个关于上载日期的索引,该索引未在这个特殊查询中使用。那么,综合指数呢

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`type`,`uid`),
  KEY `idx_upload_date DESC` (`uid`,`upload_date`)

首先,
左连接是不必要的。因此,您可以将查询编写为:

SELECT c.*
FROM ost_content c JOIN
     ost_categories2media c2m
     ON c2m.categories2media_uid = c.uid
WHERE c2m.categories2media_category_id = '53' AND
      c.conversion_status IN ('success', 'announcement') AND
      c.type IN ('serial', 'media')
ORDER BY c.upload_date DESC
LIMIT 16, 16;
不幸的是,内容表上的条件不是简单的
=
条件。如果是,建议使用
ost\u内容(转换状态、类型、uid)
索引。这可能仍然是更好的选择

另一种选择是另一种方式:在
ost\u categories2media(categories2media\u categories\u id,categories2media\u uid)
上建立索引

您可能会发现,第一个复合索引和此查询最有效:

SELECT c.*
FROM ((SELECT c.*
       FROM ost_content c JOIN
            ost_categories2media c2m
            ON c2m.categories2media_uid = c.uid
       WHERE c2m.categories2media_category_id = '53' AND
             c.conversion_status = 'success' AND
             c.type IN ('serial', 'media')
      ) UNION ALL
      (SELECT c.*
       FROM ost_content c JOIN
            ost_categories2media c2m
            ON c2m.categories2media_uid = c.uid
       WHERE c2m.categories2media_category_id = '53' AND
             c.conversion_status = 'announcement' AND
             c.type IN ('serial', 'media')
      ) 
     ) c
ORDER BY c.upload_date DESC
LIMIT 16, 16;

这看起来更复杂,但每个子查询都可以利用索引,因此可能会提高性能。

首先,不需要使用
左连接。因此,您可以将查询编写为:

SELECT c.*
FROM ost_content c JOIN
     ost_categories2media c2m
     ON c2m.categories2media_uid = c.uid
WHERE c2m.categories2media_category_id = '53' AND
      c.conversion_status IN ('success', 'announcement') AND
      c.type IN ('serial', 'media')
ORDER BY c.upload_date DESC
LIMIT 16, 16;
不幸的是,内容表上的条件不是简单的
=
条件。如果是,建议使用
ost\u内容(转换状态、类型、uid)
索引。这可能仍然是更好的选择

另一种选择是另一种方式:在
ost\u categories2media(categories2media\u categories\u id,categories2media\u uid)
上建立索引

您可能会发现,第一个复合索引和此查询最有效:

SELECT c.*
FROM ((SELECT c.*
       FROM ost_content c JOIN
            ost_categories2media c2m
            ON c2m.categories2media_uid = c.uid
       WHERE c2m.categories2media_category_id = '53' AND
             c.conversion_status = 'success' AND
             c.type IN ('serial', 'media')
      ) UNION ALL
      (SELECT c.*
       FROM ost_content c JOIN
            ost_categories2media c2m
            ON c2m.categories2media_uid = c.uid
       WHERE c2m.categories2media_category_id = '53' AND
             c.conversion_status = 'announcement' AND
             c.type IN ('serial', 'media')
      ) 
     ) c
ORDER BY c.upload_date DESC
LIMIT 16, 16;
这看起来更复杂,但每个子查询都可以利用索引,因此可能会提高性能