Mysql插入快,删除慢,索引错误
Mysql fast insert, slow delete, wrong index
我有一个事件生成了一些代表 accumulators
的数据,我称之为 transaction
。事实证明 运行 从头开始生成累加器比尝试将它们与现有累加器匹配要快得多。因此,我给了他们一个 transaction_id
,创建它们,然后在一个查询中删除以前的交易。
创建约。 table 中的 200 万行需要大约 40 秒,但是使用下面的查询删除目前大约需要 20-30 分钟。
DELETE
FROM accumulator
WHERE id_acca_set = @set_id
AND ( transaction_id != @transaction_id or transaction_id is null);
查看 innodb 状态,我在执行查询时看到以下内容。据我所知,现阶段似乎没有冲突锁。
---TRANSACTION 11535589892, ACTIVE 259 sec updating or deleting, thread declared inside InnoDB 4657
mysql tables in use 1, locked 1
29009 lock struct(s), heap size 3776720, 1195753 row lock(s), undo log entries 1195753
MySQL thread id 108262, OS thread handle 131874376460032, query id 9689717638 event_scheduler updating
accumulator
table 定义如下。我注意到它没有使用 IDX_accumulator5
,而是 IDX_accumulator3
,它不包含 transaction_id
。
CREATE TABLE acca.accumulator (
id bigint(20) NOT NULL AUTO_INCREMENT,
id_acca_set int(1) NOT NULL DEFAULT 0,
id_event bigint(20) NOT NULL DEFAULT 0,
id_back_outcome bigint(20) NOT NULL DEFAULT 0,
id_lay_outcome bigint(20) NOT NULL DEFAULT 0,
acca_id varchar(255) DEFAULT NULL,
prev_acca_id varchar(255) DEFAULT NULL,
leg_number int(11) NOT NULL,
score double DEFAULT NULL,
transaction_id varchar(255) DEFAULT NULL,
PRIMARY KEY (id),
INDEX IDX_accumulator (id_acca_set, acca_id, transaction_id),
INDEX IDX_accumulator2 (id_acca_set, leg_number, acca_id, transaction_id),
INDEX IDX_accumulator3 (id_acca_set, id_event, id_back_outcome, id_lay_outcome, leg_number),
INDEX IDX_accumulator4 (id_acca_set, prev_acca_id, id_event),
INDEX IDX_accumulator5 (id_acca_set, transaction_id),
INDEX IDX_accumulator6 (transaction_id, id_acca_set, leg_number, score)
)
ENGINE = INNODB
AUTO_INCREMENT = 242051170
AVG_ROW_LENGTH = 282
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
我在 CentOS 7 上 运行ning MySQL 5.7.13。我没有使用交换内存,还有大约 10GB 剩余可用内存,6GB 分配给 INNODB 缓冲区。 my.cnf
中的 InnoDB 设置为:
innodb_buffer_pool_size = 6G
innodb_buffer_pool_instances = 6
innodb_commit_concurrency = 4
innodb_flush_method = O_DIRECT
innodb_thread_concurrency = 8
innodb_thread_sleep_delay = 100
innodb_flush_log_at_trx_commit = 1
innodb_flush_log_at_timeout = 10
我不知道有任何 DBMS 会使用索引来解析否定谓词 (transaction_id != @transaction_id)。
我不明白你为什么要添加新记录然后删除旧记录。如果你反过来做(截断 table),那么它会花费很少的时间。如果你想确保你有数据可以依靠,那么另一种方法是重命名现有的 table 然后创建一个新的(使用原始名称)来保存新数据。
我有一个事件生成了一些代表 accumulators
的数据,我称之为 transaction
。事实证明 运行 从头开始生成累加器比尝试将它们与现有累加器匹配要快得多。因此,我给了他们一个 transaction_id
,创建它们,然后在一个查询中删除以前的交易。
创建约。 table 中的 200 万行需要大约 40 秒,但是使用下面的查询删除目前大约需要 20-30 分钟。
DELETE
FROM accumulator
WHERE id_acca_set = @set_id
AND ( transaction_id != @transaction_id or transaction_id is null);
查看 innodb 状态,我在执行查询时看到以下内容。据我所知,现阶段似乎没有冲突锁。
---TRANSACTION 11535589892, ACTIVE 259 sec updating or deleting, thread declared inside InnoDB 4657
mysql tables in use 1, locked 1
29009 lock struct(s), heap size 3776720, 1195753 row lock(s), undo log entries 1195753
MySQL thread id 108262, OS thread handle 131874376460032, query id 9689717638 event_scheduler updating
accumulator
table 定义如下。我注意到它没有使用 IDX_accumulator5
,而是 IDX_accumulator3
,它不包含 transaction_id
。
CREATE TABLE acca.accumulator (
id bigint(20) NOT NULL AUTO_INCREMENT,
id_acca_set int(1) NOT NULL DEFAULT 0,
id_event bigint(20) NOT NULL DEFAULT 0,
id_back_outcome bigint(20) NOT NULL DEFAULT 0,
id_lay_outcome bigint(20) NOT NULL DEFAULT 0,
acca_id varchar(255) DEFAULT NULL,
prev_acca_id varchar(255) DEFAULT NULL,
leg_number int(11) NOT NULL,
score double DEFAULT NULL,
transaction_id varchar(255) DEFAULT NULL,
PRIMARY KEY (id),
INDEX IDX_accumulator (id_acca_set, acca_id, transaction_id),
INDEX IDX_accumulator2 (id_acca_set, leg_number, acca_id, transaction_id),
INDEX IDX_accumulator3 (id_acca_set, id_event, id_back_outcome, id_lay_outcome, leg_number),
INDEX IDX_accumulator4 (id_acca_set, prev_acca_id, id_event),
INDEX IDX_accumulator5 (id_acca_set, transaction_id),
INDEX IDX_accumulator6 (transaction_id, id_acca_set, leg_number, score)
)
ENGINE = INNODB
AUTO_INCREMENT = 242051170
AVG_ROW_LENGTH = 282
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
我在 CentOS 7 上 运行ning MySQL 5.7.13。我没有使用交换内存,还有大约 10GB 剩余可用内存,6GB 分配给 INNODB 缓冲区。 my.cnf
中的 InnoDB 设置为:
innodb_buffer_pool_size = 6G
innodb_buffer_pool_instances = 6
innodb_commit_concurrency = 4
innodb_flush_method = O_DIRECT
innodb_thread_concurrency = 8
innodb_thread_sleep_delay = 100
innodb_flush_log_at_trx_commit = 1
innodb_flush_log_at_timeout = 10
我不知道有任何 DBMS 会使用索引来解析否定谓词 (transaction_id != @transaction_id)。
我不明白你为什么要添加新记录然后删除旧记录。如果你反过来做(截断 table),那么它会花费很少的时间。如果你想确保你有数据可以依靠,那么另一种方法是重命名现有的 table 然后创建一个新的(使用原始名称)来保存新数据。