我陷入了 MySQL 设计可扩展性问题。任何帮助将不胜感激。
要求:
在他们的社交图中存储用户关于每个用户的 SOCIAL_GRAPH 和 USER_INFO。每秒发生许多并发读取和写入。脏读可接受。
当前设计:
我们有 2 个(相关的)表。两者都是 InnoDB 进行行锁定,而不是表锁定。
USER_SOCIAL_GRAPH 表,将登录 (user_id) 映射到另一个 (related_user_id)。主键复合 user_id 和 related_user_id。
USER_INFO 表,其中包含有关每个相关用户的信息。主键是 (related_user_id)。
注 1:没有定义关系。
注2:现在每个表的大小约为1GB,分别有800万条和200万条记录。
简化表 SQL 创建:
CREATE TABLE `user_social_graph` (
`user_id` int(10) unsigned NOT NULL,
`related_user_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`related_user_id`),
KEY `user_idx` (`user_id`)
) ENGINE=InnoDB;
CREATE TABLE `user_info` (
`related_user_id` int(10) unsigned NOT NULL,
`screen_name` varchar(20) CHARACTER SET latin1 DEFAULT NULL,
[... and many other non-indexed fields irrelevant]
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`related_user_id`),
KEY `last_updated_idx` (`last_updated`)
) ENGINE=InnoDB;
MY.CFG 值集:
innodb_buffer_pool_size = 256M
key_buffer_size = 320M
注3:可用内存1GB,这2张表2GB,其他innoDB表3GB。
问题:
以下示例 SQL 语句需要访问找到的所有记录,执行需要 15 秒 (!!) 并且 num_results = 220,000:
SELECT SQL_NO_CACHE COUNT(u.related_user_id)
FROM user_info u LEFT JOIN user_socialgraph u2 ON u.related_user_id = u2.related_user_id
WHERE u2.user_id = '1'
AND u.related_user_id = u2.related_user_id
AND (NOT (u.related_user_id IS NULL));
对于计数为 30,000 的 user_id,大约需要 3 秒(!)。
EXPLAIN EXTENDED 用于 220,000 计数用户。它使用索引:
+----+-------------+-------+--------+------------------------+----------+---------+--------------------+--------+----------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+--------+------------------------+----------+---------+--------------------+--------+----------+--------------------------+
| 1 | SIMPLE | u2 | ref | user_user_idx,user_idx | user_idx | 4 | const | 157320 | 100.00 | Using where |
| 1 | SIMPLE | u | eq_ref | PRIMARY | PRIMARY | 4 | u2.related_user_id | 1 | 100.00 | Using where; Using index |
+----+-------------+-------+--------+------------------------+----------+---------+--------------------+--------+----------+--------------------------+
我们如何在不将 innodb_buffer_pool_size 设置为 5GB 的情况下加快这些速度?
谢谢!
最佳答案
user_social_graph 表没有正确索引!!!
你有:
创建表 user_social_graph
(user_id
int(10) unsigned NOT NULL,
related_user_id
int(11) NOT NULL,
主键 (user_id
,related_user_id
),
KEY user_idx
(user_id
))
引擎=InnoDB;
第二个索引是多余的,因为第一列是 user_id。您正在尝试将 related_user_id 列连接到 user_info 表。该列需要编入索引。
按如下方式更改 user_social_graphs:
创建表 user_social_graph
(user_id
int(10) unsigned NOT NULL,
related_user_id
int(11) NOT NULL,
主键 (user_id
,related_user_id
),
唯一键 related_user_idx
(related_user_id
,user_id
))
引擎=InnoDB;
这应该会改变 EXPLAIN PLAN。请记住,索引顺序很重要,具体取决于您查询列的方式。
试一试!!!
关于未将 innodb_buffer_pool_size 设置为 5GB 的 MySQL I/O 绑定(bind) InnoDB 查询优化问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5613281/