MySQL 性能 - 从大 table 中选择和删除
MySQL performance - Selecting and deleting from a large table
我有一个很大的 table,叫做 "queue"。它现在有 1200 万条记录。
CREATE TABLE `queue` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userid` varchar(64) DEFAULT NULL,
`action` varchar(32) DEFAULT NULL,
`target` varchar(64) DEFAULT NULL,
`name` varchar(64) DEFAULT NULL,
`state` int(11) DEFAULT '0',
`timestamp` int(11) DEFAULT '0',
`errors` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_unique` (`userid`,`action`,`target`),
KEY `idx_userid` (`userid`),
KEY `idx_state` (`state`)
) ENGINE=InnoDB;
多名 PHP 名工人 (150) 同时使用此 table。
他们 select 一条记录,使用 selected 数据执行网络请求,然后删除该记录。
我从 select 和删除查询中得到混合执行时间。删除命令是否锁定 table?
这种情况的最佳方法是什么?
SELECT记录+NETWORK请求+DELETE记录
SELECT 记录 + 网络请求 + 将记录标记为已完成 + 不时使用 cron 删除已完成的记录(我不想要更大的 table) .
注意:队列每分钟获取新记录,但 INSERT 查询不是这里的问题。
感谢任何帮助。
"Don't queue it, just do it"。也就是说,如果任务相当快,最好只是执行操作而不是排队。数据库没有很好的排队机制。
DELETE
不锁定 InnoDB table。但是,你可以写一个看起来很调皮的DELETE
。让我们看看您的实际 SQL,以便我们改进它。
12M 条记录?这是一个巨大的积压;怎么了?
缩小数据类型,使 table 不是千兆字节:
action
只是一小部分可能的值?将其标准化为 1 字节 ENUM
或 TINYINT UNSIGNED
.
- 同上
state
-- 它肯定不需要 4 字节代码吗?
- 不需要
INDEX(userid)
,因为已经有一个以userid
开头的索引(UNIQUE
)。
- 如果
state
只有几个值,索引将不会被使用。让我们看看您的入队和出队查询,以便我们可以讨论如何摆脱该索引或使其成为 'composite'(并且有用)。
MAX(id)
的当前值是多少? INT UNSIGNED
是否有超过您目前约 40 亿的限制?
- PHP如何使用队列?它是否通过 InnoDB 事务挂在项目上?这打败了任何并行性!或者它会改变
state
。向我们展示代码;也许锁定和解锁可以减少侵入性。应该可以 运行 一个自动提交的 UPDATE
来获取一行及其 id
。然后,稍后,执行自动提交 DELETE
,影响很小。
- 我没有看到用于抓取挂起项目的良好索引。再一次,让我们看看代码。
- 150 似乎很多 -- 您是否尝试过 更少的?他们可能互相绊倒。
- Slowlog 是否打开(
long_query_time
的值较低)?如果是这样,我想知道 'worst' 查询是什么。在这种情况下,答案可能会令人惊讶。
我有一个很大的 table,叫做 "queue"。它现在有 1200 万条记录。
CREATE TABLE `queue` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userid` varchar(64) DEFAULT NULL,
`action` varchar(32) DEFAULT NULL,
`target` varchar(64) DEFAULT NULL,
`name` varchar(64) DEFAULT NULL,
`state` int(11) DEFAULT '0',
`timestamp` int(11) DEFAULT '0',
`errors` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_unique` (`userid`,`action`,`target`),
KEY `idx_userid` (`userid`),
KEY `idx_state` (`state`)
) ENGINE=InnoDB;
多名 PHP 名工人 (150) 同时使用此 table。
他们 select 一条记录,使用 selected 数据执行网络请求,然后删除该记录。
我从 select 和删除查询中得到混合执行时间。删除命令是否锁定 table?
这种情况的最佳方法是什么?
SELECT记录+NETWORK请求+DELETE记录
SELECT 记录 + 网络请求 + 将记录标记为已完成 + 不时使用 cron 删除已完成的记录(我不想要更大的 table) .
注意:队列每分钟获取新记录,但 INSERT 查询不是这里的问题。
感谢任何帮助。
"Don't queue it, just do it"。也就是说,如果任务相当快,最好只是执行操作而不是排队。数据库没有很好的排队机制。
DELETE
不锁定 InnoDB table。但是,你可以写一个看起来很调皮的DELETE
。让我们看看您的实际 SQL,以便我们改进它。
12M 条记录?这是一个巨大的积压;怎么了?
缩小数据类型,使 table 不是千兆字节:
action
只是一小部分可能的值?将其标准化为 1 字节ENUM
或TINYINT UNSIGNED
.- 同上
state
-- 它肯定不需要 4 字节代码吗? - 不需要
INDEX(userid)
,因为已经有一个以userid
开头的索引(UNIQUE
)。 - 如果
state
只有几个值,索引将不会被使用。让我们看看您的入队和出队查询,以便我们可以讨论如何摆脱该索引或使其成为 'composite'(并且有用)。 MAX(id)
的当前值是多少?INT UNSIGNED
是否有超过您目前约 40 亿的限制?- PHP如何使用队列?它是否通过 InnoDB 事务挂在项目上?这打败了任何并行性!或者它会改变
state
。向我们展示代码;也许锁定和解锁可以减少侵入性。应该可以 运行 一个自动提交的UPDATE
来获取一行及其id
。然后,稍后,执行自动提交DELETE
,影响很小。 - 我没有看到用于抓取挂起项目的良好索引。再一次,让我们看看代码。
- 150 似乎很多 -- 您是否尝试过 更少的?他们可能互相绊倒。
- Slowlog 是否打开(
long_query_time
的值较低)?如果是这样,我想知道 'worst' 查询是什么。在这种情况下,答案可能会令人惊讶。