我需要将TSV文件中的数据加载到具有7个外键的表中。我在网上发现了一个建议,它可以通过一个代理表来完成,该代理表具有与输入文件匹配的列和插入事件上的触发器,该事件将数据填充到目标表及其父节点具有FK约束。我开始测试它,我注意到父表的PK ID增加了1以上,我的意思是代替预期的1,2,3,...的序列...我得到类似1,63,539的东西, ......看看我的触发器代码:
create trigger trig1 before insert on temp_table
for each row
begin
-- Set FKs
declare ts_id BIGINT UNSIGNED;
declare cluster_id BIGINT UNSIGNED;
declare queue_id BIGINT UNSIGNED;
declare service_class_id BIGINT UNSIGNED;
declare project_id BIGINT UNSIGNED;
declare job_group_id BIGINT UNSIGNED;
declare user_id BIGINT UNSIGNED;
insert into timeline (ts) values (NEW.ts) on duplicate key update id=last_insert_id(id);
select last_insert_id() into ts_id;
insert into clusters (name) values (NEW.cluster_name) on duplicate key update id=last_insert_id(id);
select last_insert_id() into cluster_id;
insert into queues (name) values (NEW.queue_name) on duplicate key update id=last_insert_id(id);
select last_insert_id() into queue_id;
insert into service_classes (name) values (NEW.service_class) on duplicate key update id=last_insert_id(id);
select last_insert_id() into service_class_id;
insert into projects (code) values (NEW.project_code) on duplicate key update id=last_insert_id(id);
select last_insert_id() into project_id;
insert into job_groups (name) values (NEW.job_group) on duplicate key update id=last_insert_id(id);
select last_insert_id() into job_group_id;
insert into users (name) values (NEW.user_name) on duplicate key update id=last_insert_id(id);
select last_insert_id() into user_id;
-- Insert a new row to the dest table
insert into dest_table values(ts_id, cluster_id, queue_id, service_class_id, project_id, job_group_id, user_id, NEW.job_count, NEW.slot_count, NEW.mem_req, NEW.mem_used);
end;
在我看来,在语句'insert into ... on duplicate key update id = last_insert_id(id);'每当发生重复插入时,即使父表没有变化,'update'也会影响最后一个插入ID。请让我知道你的想法 - 我猜测这个auto_increment行为是否正确以及如何防止这样的问题。在生产中,这个问题可能导致父表中的PK达到预期的最大值,所以我想避免这种情况。
答案 0 :(得分:1)
这些丢失的值是已知的记录限制。
请参阅以下文档: http://dev.mysql.com/doc/refman/5.6/en/innodb-auto-increment-configurable.html
我希望在此问题中的先前讨论中提出了一些避免此问题的替代方法: prevent autoincrement on MYSQL duplicate insert
答案 1 :(得分:1)
在@TrentLloyd指向我的MySQL doc http://dev.mysql.com/doc/refman/5.6/en/innodb-auto-increment-configurable.html中,我发现这种行为取决于系统变量innodb_autoinc_lock_mode的值:
所以innodb_autoinc_lock_mode = 0可以满足我的需求。不幸的是,这个参数的默认值是1,它不能在会话中更改,但只能在my.cnf中或作为启动命令参数,因此需要重新启动并重新启动MySQL服务。
我想到的解决方法是从所有父表上的ID中删除auto_increment并重写触发器:
create trigger jrun_trig before insert on jrun_tmp
for each row
begin
-- Set FKs
declare ts_id INT UNSIGNED;
declare cluster_id INT UNSIGNED;
declare queue_id INT UNSIGNED;
declare service_class_id INT UNSIGNED;
declare project_id INT UNSIGNED;
declare job_group_id INT UNSIGNED;
declare user_id INT UNSIGNED;
if NEW.ts is NULL then set ts_id = NULL;
else
select id into ts_id from timeline where ts = NEW.ts limit 1;
if ts_id is NULL then
select ifnull(max(id), 0) + 1 into ts_id from timeline;
insert into timeline values (ts_id, NEW.ts);
end if;
end if;
if NEW.cluster_name is NULL then set cluster_id = NULL;
else
select id into cluster_id from clusters where name = NEW.cluster_name limit 1;
if cluster_id is NULL then
select ifnull(max(id), 0) + 1 into cluster_id from clusters;
insert into clusters values (cluster_id, NEW.cluster_name);
end if;
end if;
if NEW.queue_name is NULL then set queue_id = NULL;
else
select id into queue_id from queues where name = NEW.queue_name limit 1;
if queue_id is NULL then
select ifnull(max(id), 0) + 1 into queue_id from queues;
insert into queues values (queue_id, NEW.queue_name);
end if;
end if;
if NEW.service_class is NULL then set service_class_id = NULL;
else
select id into service_class_id from service_classes where name = NEW.service_class limit 1;
if service_class_id is NULL then
select ifnull(max(id), 0) + 1 into service_class_id from service_classes;
insert into service_classes values (service_class_id, NEW.service_class);
end if;
end if;
if NEW.project_code is NULL then set project_id = NULL;
else
select id into project_id from projects where code = NEW.project_code limit 1;
if project_id is NULL then
select ifnull(max(id), 0) + 1 into project_id from projects;
insert into projects (id, code) values (project_id, NEW.project_code);
end if;
end if;
if NEW.job_group is NULL then set job_group_id = NULL;
else
select id into job_group_id from job_groups where name = NEW.job_group limit 1;
if job_group_id is NULL then
select ifnull(max(id), 0) + 1 into job_group_id from job_groups;
insert into job_groups values (job_group_id, NEW.job_group);
end if;
end if;
if NEW.user_name is NULL then set user_id = NULL;
else
select id into user_id from users where name = NEW.user_name limit 1;
if user_id is NULL then
select ifnull(max(id), 0) + 1 into user_id from users;
insert into users values (user_id, NEW.user_name);
end if;
end if;
-- Insert a new row to the dest table
insert ignore into jrun values(ts_id, cluster_id, queue_id, service_class_id, project_id, job_group_id, user_id, NEW.job_count, NEW.slot_count, NEW.mem_req, NEW.mem_used);
end;
触发器现在有更多的线,但它完全解决了我的PK列间隙问题。