MySQL I/O绑定InnoDB查询优化问题,无需将InnoDB_buffer_pool_size设置为5GB
我陷入了MySQL设计的可伸缩性问题。任何帮助都将不胜感激 要求:MySQL I/O绑定InnoDB查询优化问题,无需将InnoDB_buffer_pool_size设置为5GB,mysql,database,database-design,Mysql,Database,Database Design,我陷入了MySQL设计的可伸缩性问题。任何帮助都将不胜感激 要求: 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
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;
innodb_buffer_pool_size = 256M
key_buffer_size = 320M
在用户的社交图中存储用户的社交图和每个用户的用户信息。每秒发生许多并发读写操作。肮脏的阅读是可以接受的
当前设计:
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;
innodb_buffer_pool_size = 256M
key_buffer_size = 320M
我们有两个(相关)表格。两个InnoDB都用于行锁定,而不是表锁定
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;
innodb_buffer_pool_size = 256M
key_buffer_size = 320M
MY.CFG值集:
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;
innodb_buffer_pool_size = 256M
key_buffer_size = 320M
注3:可用内存为1GB,这两个表为2GB,其他innoDB表为3GB
问题:
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;
innodb_buffer_pool_size = 256M
key_buffer_size = 320M
以下示例SQL语句需要访问找到的所有记录,执行该语句需要15秒(!!),num_results=220000:
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));
对于计数为30000的用户id,大约需要3秒(!)
解释针对220000计数用户的扩展。它使用指数:
+----+-------------+-------+--------+------------------------+----------+---------+--------------------+--------+----------+--------------------------+
| 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的情况下加快这些速度
谢谢大家! 用户\u社交\u图表未正确索引 你有: 创建表格
user\u social\u图表
(user\u id
int(10)无符号非空,
相关用户id
int(11)不为空,
主键(用户id
,相关用户id
),
按键user\u idx
(user\u id
)
引擎=InnoDB
第二个索引是多余的,因为第一列是user\u id。您正在尝试将相关的\u user\u id列加入到user\u info表中。该列需要编制索引
按如下方式更改用户\社交\图:
创建表格user\u social\u图表
(user\u id
int(10)无符号非空,
相关用户id
int(11)不为空,
主键(用户id
,相关用户id
),
唯一键相关用户id
(相关用户id
,用户id
)
引擎=InnoDB
这应该会改变计划。请记住,索引顺序取决于查询列的方式
试试看
MySQL版本是什么?其手册包含加速语句和代码的重要信息
将您的范例更改为能够管理TB级表的数据仓库。使用免费工具或应用程序将遗留的MySQL数据库迁移到新的范例。这是一个例子:许多其他(免费和商业)
PostgreSQL不是商业化的,有很多工具可以将MySQL迁移到它
你是对的。该指数不是最佳选择。我做了你建议的改变,但没有用。EXPLAIN计划看起来更好,但它仍然是I/O绑定的,速度很慢(和以前一样)。我不得不使用FORCE KEY FOR JOIN(related_user_idx)让MySQL使用新索引,现在显示在解释中。有什么想法吗?为什么MySQL不使用COUNT()的索引?我至少会将innodb_buffer_pool_大小增加一倍,达到512M。另外,我会将innodb_log_file_大小设置为128M。在/etc/my.cnf中设置这些值后,请确保执行以下操作:1)关闭mysql,2)rm/var/lib/mysql/ib_logfile*,3)针对InnoDB从不使用索引重新启动mysql.COUNT()。当您在InnoDB表中执行“从tblname显示索引”时,每次都会得到不同的基数。这是因为为了MySQL查询优化器的缘故,InnoDB存储引擎确实会将索引潜入索引以猜测基数。因此,通过设计获得表计数时,该索引被认为是完全不可靠的。因此,MySQL每次都会针对InnoDB表启动一次完整的表扫描。感谢您的响应。innodb_buffer_pool_size设置为512M时,速度确实提高了2倍。但我肯定我们错过了什么。正如您从最初的EXPLAIN输出中看到的,它使用的是索引,那么为什么它要从磁盘读取记录来计数呢?页面刚刚更新了您的新注释。关于计数和索引,您是对的。我有一个想法,我不是100%确定如何执行。如果我将这些表转换为MyISAM,是否有办法解决表锁定问题,以便INSERT、DELETE和UPDATE语句几乎可以同时运行?我猜快速和延迟关键字会有所帮助。注意:解释中显示的“user\u user\u idx”与user\u social\u图表的主关键字相同。感谢您的回答,但似乎没有正确的答案。为了使执行时间可接受,我设置了以下my.cfg值:innodb_buffer_pool_size=612M,innodb_flush_method=O_DIRECT(跳过双缓存),innodb_locks_unsafe_for_binlog=1(请参阅)。不是很容易扩展,但是可以接受。您能澄清一下您希望通过此查询实现什么吗?例如,如果您只是想计算ID为1的用户的相关用户ID的数量,那么很简单:从user_-social_图中选择count(*),其中user_-ID=1。此外,您的JOIN和WHERE条件是冗余的。此外,(NOT(u.related_-user_-ID为NULL))中的条件是冗余的,因为相关的用户id被定义为非空。谢谢分享。我现在并不是真的想换一个不同的数据库系统,因为我相信MySQL可以被调整以处理我们现在的几个场景。请你详细说明第二点好吗。也许是链接?另外,为什么您认为PostgreSQL可以解决并发问题?