2

我有几个查询可以使用一些优化,因为它们需要相当长的时间,所以在阅读了这个站点上的许多帖子后,我开始修改我的架构并添加/更改索引以适当地加快查询速度。在大多数情况下,我都取得了巨大的成功,但是在这种特殊情况下,我被卡住了,我不确定自己做错了什么。

我有一张表,里面有大约 350 万行。

select count(*) from post;
+----------+
| count(*) |
+----------+
|  3652904 |
+----------+

并创建如下:

Create Table: CREATE TABLE `post` (
  `id` varchar(255) NOT NULL DEFAULT '',
  `page_id` bigint(20) NOT NULL DEFAULT '0',
  `post_id` bigint(20) NOT NULL DEFAULT '0',
  `type` varchar(45) CHARACTER SET latin1 NOT NULL,
  ...
  `created_time` timestamp NULL DEFAULT NULL,
  `updated_time` timestamp NULL DEFAULT NULL,
  `timestamp` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`page_id`,`post_id`),
  KEY `created_time` (`created_time`),
  KEY `target_id` (`target_id`),
  KEY `id` (`id`) USING BTREE
) ENGINE=TokuDB DEFAULT CHARSET=utf8
/*!50100 PARTITION BY HASH (page_id)
PARTITIONS 10 */

另一个表的行数很少,创建如下:

select count(*) from privacy;
+----------+
| count(*) |
+----------+
|    19093 |
+----------+

Create Table: CREATE TABLE `privacy` (
  `id` varchar(255) CHARACTER SET latin1 NOT NULL,
  `page_id` bigint(20) DEFAULT '0',
  `description` text CHARACTER SET latin1,
  `value` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
  `allow` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
  `deny` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
  `json` text CHARACTER SET latin1,
  `timestamp` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `page_id` (`page_id`)
) ENGINE=TokuDB DEFAULT CHARSET=utf8

我要优化的选择如下:

explain partitions 
SELECT   
  post.id,  post.type,  privacy.description  
FROM   
  post 
LEFT JOIN privacy ON privacy.id = post.id  
WHERE post.page_id = 12854644836;
+----+-------------+---------+------------+------+---------------+---------+---------+-------+-------+-------+
| id | select_type | table   | partitions | type | possible_keys | key     | key_len | ref   | rows  | Extra |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+-------+-------+
|  1 | SIMPLE      | post    | p6         | ref  | PRIMARY       | PRIMARY | 8       | const | 34685 |       |
|  1 | SIMPLE      | privacy | NULL       | ALL  | NULL          | NULL    | NULL    | NULL  | 19093 |       |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+-------+-------+

不幸的是,这个选择需要几分钟,我不知道为什么。我注意到解释没有选择主键,我想知道这是否是由于两个表之间的字符集不同。即便如此,从解释来看也不应该涉及那么多行,但执行起来仍然需要那么长时间。

16754 rows in set (5 min 33.68 sec)

仅从表格中进行选择就非常快。

select * from post where page_id = 12854644836;
16754 rows in set (0.22 sec)

select * from privacy where page_id = 12854644836;
234 rows in set (0.01 sec)

这个网站上的一些 MySQL 大师能否为我指明正确的方向?谢谢 :)

4

2 回答 2

2

这是因为该id列在privacy 表中定义为latin1,在posts 表中定义为utf8。

MySQL 必须对连接的 id 列进行字符集转换,因此它不能使用索引。更改字符集,它将解决问题。

于 2012-07-08T00:08:00.140 回答
0

MySQL 不能在单个查询中为同一个表引用使用多个索引。您将需要在帖子表上构建一个复合索引,(id,page_id)因为需要在两列中搜索此查询(第一列用于连接,第二列用于过滤条件)。

于 2012-07-07T23:50:59.027 回答