MySQL选择优化

MySQL选择优化,mysql,optimization,select,tokudb,Mysql,Optimization,Select,Tokudb,我有几个查询可能需要一些优化,因为它们需要相当长的时间,所以在阅读了这个网站上的许多帖子后,我开始修改我的模式,并添加/更改索引以适当地加快查询速度。在大多数情况下,我取得了巨大的成功,但在这个特殊的情况下,我陷入困境,我不知道我做错了什么 我有一个大约有350万行的表格 select count(*) from post; +----------+ | count(*) | +----------+ | 3652904 | +----------+ 并创建如下所示: Create Tabl

我有几个查询可能需要一些优化,因为它们需要相当长的时间,所以在阅读了这个网站上的许多帖子后,我开始修改我的模式,并添加/更改索引以适当地加快查询速度。在大多数情况下,我取得了巨大的成功,但在这个特殊的情况下,我陷入困境,我不知道我做错了什么

我有一个大约有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 |       |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+-------+-------+
我尝试优化的选择如下所示:

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 |       |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+-------+-------+
不幸的是,这个选择需要几分钟,我不知道为什么。我注意到explain没有提取主键,我想知道这是否是由于两个表之间的字符集不同造成的。即使如此,从解释中也不应该涉及那么多行,但执行仍然需要那么长的时间

16754 rows in set (5 min 33.68 sec)
仅从表中选择就相当快

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

这个网站上的一些MySQL专家能为我指出正确的方向吗?
谢谢:)

MySQL不能在一个查询中对同一个表引用使用多个索引。您需要在posts表的
(id,page_id)
上建立一个复合索引,因为需要搜索这两列来进行查询(第一列用于连接,第二列用于筛选条件)。

这是因为
id
列在隐私表中定义为拉丁1,在posts表中定义为utf8


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

谢谢!执行此更改会将查询时间降至0.20秒。仅供参考,如果您这样做,您可以看到问题:解释扩展;显示警告;这将显示mysql在哪里进行字符集转换。谢谢,这也非常有用。现在我已经把大多数查询的索引更改为复合查询,我可以看到全面的速度提升。你也应该考虑做这个索引聚类(或者增加它的类型以使它成为覆盖索引)。您还没有为post表包含整个模式,因此集群索引可能太多,无法满足您的需要。