답변:
을 사용하는 것이 좋습니다 INSERT...ON DUPLICATE KEY UPDATE
.
을 사용 INSERT IGNORE
하면 행이 중복 된 키가 있으면 행이 실제로 삽입되지 않습니다. 그러나 문은 오류를 생성하지 않습니다. 대신 경고를 생성합니다. 이러한 경우는 다음과 같습니다.
PRIMARY KEY
또는 UNIQUE
제약 조건이 있는 열에 중복 키 삽입NOT NULL
제약 조건이 있는 열에 NULL을 삽입합니다 .을 사용하는 REPLACE
경우 MySQL은 실제로 내부적 으로 DELETE
다음을 수행하므로 INSERT
예기치 않은 부작용이 있습니다.
REPLACE
.DELETE
실행되는 트리거 는 불필요하게 실행됩니다.수정 : 모두 REPLACE
와 INSERT...ON DUPLICATE KEY UPDATE
표준이 아닌, MySQL의 독점 발명의 특정입니다. ANSI SQL 2003은 MERGE
동일한 요구를 해결할 수 있는 명령문을 정의 하지만 MySQL은이 MERGE
명령문을 지원하지 않습니다 .
사용자가이 게시물을 수정하려고했습니다 (관리자가 편집을 거부했습니다). 수정 사항 INSERT...ON DUPLICATE KEY UPDATE
에 새 자동 증분 ID가 할당 되는 소유권 주장을 추가하려고했습니다 . 새 ID가 생성 되는 것은 사실 이지만 변경된 행에는 사용되지 않습니다.
Percona Server 5.5.28로 테스트 한 아래 데모를 참조하십시오. 구성 변수 innodb_autoinc_lock_mode=1
(기본값) :
mysql> create table foo (id serial primary key, u int, unique key (u));
mysql> insert into foo (u) values (10);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 10 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
mysql> insert into foo (u) values (10) on duplicate key update u = 20;
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
위의 내용은 IODKU 문이 중복을 감지하고 값을 변경하기 위해 업데이트를 호출 함을 보여줍니다 u
. (가) 주 AUTO_INCREMENT=3
에 id가 생성 된 나타내지 만 행에 사용되지.
반면 REPLACE
원래 행을 삭제하고 새 행을 삽입 하여 새 자동 증분 ID를 생성 하고 저장합니다.
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+
INSERT ... ON DUPLICATE KEY UPDATE ...
진술 로 채워진 테이블을 보았습니다 . 많은 데이터가 복제되어 AI PK의 한 인스턴스가 두 행 사이에서 17,029,941에서 46,271,740으로 증가했습니다. 매번 새로운 AI를 생성하면 범위를 매우 빠르게 채울 수 있으며 정리해야합니다. 이 테이블은 2 주 전입니다!
이 모든 것이 무엇을 의미하는지 알고 싶다면 여기에 모든 것이 있습니다.
CREATE TABLE `users_partners` (
`uid` int(11) NOT NULL DEFAULT '0',
`pid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`uid`,`pid`),
KEY `partner_user` (`pid`,`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
기본 키는이 빠른 참조 테이블의 두 열을 기반으로합니다. 기본 키에는 고유 한 값이 필요합니다.
의 시작하자:
INSERT INTO users_partners (uid,pid) VALUES (1,1);
...1 row(s) affected
INSERT INTO users_partners (uid,pid) VALUES (1,1);
...Error Code : 1062
...Duplicate entry '1-1' for key 'PRIMARY'
INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1);
...0 row(s) affected
INSERT INTO users_partners (uid,pid) VALUES (1,1) ON DUPLICATE KEY UPDATE uid=uid
...0 row(s) affected
위의 항목은 열을 자체와 동일하게 설정하여 추가 작업을 너무 많이 저장했으며 실제로 업데이트 할 필요는 없습니다.
REPLACE INTO users_partners (uid,pid) VALUES (1,1)
...2 row(s) affected
이제 여러 행 테스트가 있습니다.
INSERT INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...Error Code : 1062
...Duplicate entry '1-1' for key 'PRIMARY'
INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...3 row(s) affected
콘솔에서 다른 메시지가 생성되지 않았으며 이제 테이블 데이터에 4 개의 값이 있습니다. 나는 같은 경기장에서 테스트 할 수 있도록 (1,1)을 제외한 모든 것을 삭제했습니다.
INSERT INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4) ON DUPLICATE KEY UPDATE uid=uid
...3 row(s) affected
REPLACE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...5 row(s) affected
그래서 당신은 그것을 가지고 있습니다. 데이터가 거의없고 프로덕션이 아닌 새로운 테이블에서이 작업이 모두 수행 되었기 때문에 실행 시간은 미시적이며 관련이 없었습니다. 실제 데이터를 가진 사람은 누구나 기여할 수 있습니다.
INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
.
추가해야 할 중요한 사항 : INSERT IGNORE를 사용할 때 주요 위반 사항이있는 경우 MySQL은 경고를 발생시키지 않습니다!
예를 들어 한 번에 하나의 결함이있는 레코드를 100 개 삽입하려고하면 대화식 모드가됩니다.
Query OK, 99 rows affected (0.04 sec)
Records: 100 Duplicates: 1 Warnings: 0
보다시피 경고 없음! 이 동작은 공식 Mysql Documentation에 잘못 설명되어 있습니다.
스크립트에 정보를 제공해야하는 경우 (키 위반으로 인해) 일부 레코드가 추가되지 않은 경우 mysql_info ()를 호출하여 "중복"값에 대해 구문 분석해야합니다.
mysqli_affected_rows()
하는 경우 INSERT
실제로 발생 했는지 확인하는 데 사용해야 합니다 .
Cannot add or update a child row: a foreign key constraint fails
더 행 (심지어 유효한 것)이 추가되지 않습니다.
INSERT IGNORE
중복 키는 오류나 경고없이 무시됩니다.
나는 일상적으로를 사용 INSERT IGNORE
하며, 당신이 찾고있는 행동의 종류와 똑같이 들립니다. 인덱스 충돌을 일으키는 행이 삽입되지 않고 프로그램을 적절하게 계획하는 한 문제가 발생하지 않습니다.
나는 이것이 오래되었다는 것을 알고 있지만 INSERT..IGNORE에 대한 정보를 찾으려고 할 때 나와 같은 사람이이 페이지에 도착하는 경우이 메모를 추가합니다.
위에서 언급 한 것처럼 INSERT..IGNORE를 사용하면 INSERT 문을 실행하는 동안 발생하는 오류가 대신 경고로 처리됩니다.
명시 적으로 언급되지 않은 한 가지는 INSERT..IGNORE가 삽입 될 때 유효하지 않은 값이 가장 가까운 값으로 조정된다는 것입니다 (유효하지 않은 값은 IGNORE 키워드를 사용하지 않으면 쿼리가 중단됩니다).
중복 키 업데이트시 실제로 는 표준 이 아닙니다 . REPLACE만큼이나 표준입니다. SQL MERGE를 참조하십시오 .
기본적으로 두 명령은 표준 명령의 대체 구문 버전입니다.
Replace
옵션처럼 보입니다. 또는 당신은 확인할 수 있습니다
IF NOT EXISTS(QUERY) Then INSERT
삽입 또는 삭제 후 삽입합니다. IF NOT EXISTS
먼저 확인 을하는 경향이 있습니다.
REPLACE
일치하는 테이블의 모든 행을 삭제 어떤 PRIMARY
또는 UNIQUE
, 키 다음 INSERTs
. 이것은 IODKU보다 훨씬 더 많은 작업입니다.
테이블과 기본 키 또는 고유 인덱스의 충돌에 삽입하려면 해당 행을 삽입하는 대신 충돌하는 행을 업데이트합니다.
통사론:
insert into table1 set column1 = a, column2 = b on duplicate update column2 = c;
이제이 insert 문은 앞에서 본 것과 다르게 보일 수 있습니다. 이 insert 문은 a와 b의 값을 가진 table1에 행을 각각 column1과 column2에 삽입하려고합니다.
이 문장을 깊이 이해하자 :
예를 들면 다음과 같습니다. 여기서 column1은 table1의 기본 키로 정의됩니다.
이제 table1에 column1에“a”값을 가진 행이없는 경우. 따라서이 명령문은 table1에 행을 삽입합니다.
이제 table1에 column2에 값 "a"가있는 행이 있습니다. 따라서이 명령문은 행의 column2 값을“c”로 업데이트하며 여기서 column1 값은“a”입니다.
따라서 새 행을 삽입하려면 기본 키 또는 고유 인덱스의 충돌에서 해당 행을 업데이트하십시오.
이 링크에 대해 자세히 알아보십시오
INSERT...ON DUPLICATE KEY UPDATE
예기치 않은 예외 관리를 방지하기 위해 선호됩니다.
내 경우에는 내가 알고 col1
및 col2
고유 복합 인덱스를 확인합니다.
오류를 추적하지만 중복에 대한 예외는 발생하지 않습니다. 성능과 관련하여 MySQL이이를 인식하고 업데이트하지 않는 것과 동일한 값으로 업데이트하는 것이 효율적입니다.
INSERT INTO table
(col1, col2, col3, col4)
VALUES
(?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
col1 = VALUES(col1),
col2 = VALUES(col2)
이 접근법을 사용하는 아이디어는 phpdelusions.net/pdo 의 의견에서 비롯되었습니다 .