MySQL : auto_increment가 왜 기본 키로 제한됩니까?


10

MySQL이 auto_increment 열을 기본 키로 제한한다는 것을 알고 있습니다. 왜 이런거야? 필자의 첫 번째 생각은 성능 제한이라는 것입니다.이 값을 얻기 위해 잠겨 야 할 카운터 테이블이있을 수 있기 때문입니다.

같은 테이블에 여러 auto_increment 열을 가질 수없는 이유는 무엇입니까?

감사.


방금 거래에서 @pop을 사용하는 것을 잊어 버렸습니다. 나는 예제를 다시 시도하고 내 대답의 맨 아래에 게시했습니다 !!!
RolandoMySQLDBA 2016 년

금요일 밤에별로하지 않는 MySQL을 사용하여 즉시 생각하게하기 때문에이 질문이 마음에 듭니다. +1 !!!
RolandoMySQLDBA 2016 년

답변:


9

기본 키가 아닌 auto_increment 열을 원하는 이유는 무엇입니까?

정의에 따라 열을 자동 증분으로 만들려면 해당 열에 의미있는 데이터를 저장하지 않습니다. 의미없는 정보를 저장하는 것이 합리적 일 경우는 합성 기본 키를 가지려는 특별한 경우입니다. 이 경우 정보의 부족은 누군가가 미래에 와서 일부 개체의 일부 속성이 변경되어 데이터를 변경하려는 위험이 없기 때문에 이점이 있습니다.

동일한 테이블에 여러 auto_increment 열이 있으면 더 이상하게 보입니다. 두 열의 데이터는 동일합니다. 동일한 알고리즘에 의해 생성되고 결국에는 동시에 채워집니다. 동시 세션이 충분하면 동기화가 약간 벗어날 수있는 구현을 생각해 낼 수 있다고 가정합니다. 그러나 그것이 응용 프로그램에서 어떻게 유용할지 상상할 수 없습니다.


그것은 이론적 인 질문에 가깝습니다. 여러 auto_increment 열을 실제로 사용할 수는 없었습니다. 단지 불가능한 이유에 대한 사람들의 설명을 듣고 싶었습니다. 답변을 주셔서 감사합니다. :)
Christopher Armstrong

2
"기본 키가 아닌 auto_increment 열을 원하는 이유는 무엇입니까?" 개인적으로 몇 가지 이유를 생각할 수 있습니다. 그러나 그것은 OT입니다. :-)
Denis de Bernardy 2016 년

나는 지금 이와 같은 일을하고 있으며 의미없는 데이터는 아닙니다. 테이블에 삽입 된 모든 레코드 수를 알아야하지만 더 유용한 기본 키가 이미 있습니다. 이렇게하면 모든 새 레코드의 가치가 그대로 유지되므로 문제가 해결됩니다. (약한) 유추는 "당신은 우리의 10,000 번째 고객"요구 사항입니다. 고객이 시간이 지남에 따라 삭제되므로 COUNT (*)이 유효하지 않습니다.
Cylindric

기본 키가 아닌 auto_increment 열을 원하는 이유는 무엇입니까?
phil_w

2
기본 키가 아닌 auto_increment 열을 원하는 이유는 무엇입니까? 가능한 이유는 다음과 같습니다. PK는 물리적으로 행을 정렬하는 데에도 사용되기 때문입니다. 예 : 사용자를위한 메시지를 저장한다고 가정 해 봅시다. 사용자 당 모든 메시지를 읽어야하므로 효율적으로 검색 할 수 있습니다. 테이블 메시지 (사용자 ID, TXT, 기본 키 (사용자 ID)) 작성 : PK로 InnoDB의 종류 그들 당신은 그렇게 할 수 있기 때문에
phil_w

8

실제로 AUTO_INCREMENT 속성은 PRIMARY KEY (더 이상)로 제한되지 않습니다. 예전 버전에서는 -3.23, 아마도 4.0이었습니다. 4.1 이후 모든 버전에 대한 MySQL 매뉴얼 은 여전히 다음과 같습니다.

테이블 당 하나의 AUTO_INCREMENT 열만있을 수 있으며 인덱스되어야하며 DEFAULT 값을 가질 수 없습니다.

따라서 기본 키가 아닌 테이블에 AUTO_INCREMENT 열을 실제로 가질 수 있습니다. 이해가 되더라도 다른 주제입니다.

또한 AUTO_INCREMENT 열은 항상 정수 유형이어야하며 (기술적으로 부동 소수점 유형도 허용됨) UNSIGNED 여야합니다. SIGNED 형식은 키 공간의 절반을 낭비 할뿐만 아니라 실수로 음수 값을 삽입하면 큰 문제가 발생할 수 있습니다.

마지막으로 MySQL 4.1 이상 은 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE에 대한 타입 별칭 SERIAL 을 정의합니다 .


1
auto_increment가 PK로 제한되지 않는다는 사실에 대해 +1입니다. 대리 키에 음수를 사용하면 왜 "거대한 문제"가 발생한다고 생각하는지 잘 모르겠습니다.
nvogel

4

다른 데이터베이스에는 auto_increment를 제공하기위한 고유 한 접근 방식이 있기 때문에 이것은 흥미로운 질문입니다.

MySQL : 하나의 auto_increment 키만 생성되어 테이블에서 행을 고유하게 식별합니다. 이유 뒤에는 설명이 많지 않지만 구현 만 있습니다. 데이터 유형에 따라 auto_increment 값은 데이터 유형의 길이 (바이트)로 고정됩니다.

  • 최대 TINYINT는 127입니다
  • 최대 부호없는 색조는 255입니다.
  • 최대 INT는 2147483647입니다.
  • 부호없는 최대 값은 4294967295입니다.

PostgreSQL

내부 데이터 유형 시리얼은 1에서 2,147,483,647로 자동 증분하는 데 사용됩니다. 더 큰 범위는 더 큰 직렬을 사용하여 허용됩니다.

Oracle : SEQUENCE라는 스키마 객체는 단순히 nextval 함수를 소환하여 새로운 숫자를 생성 할 수 있습니다. PostgreSQL에는 이러한 메커니즘이 있습니다.

다음은 다른 DB가 지정하는 방법을 제공하는 멋진 URL입니다. http://www.w3schools.com/sql/sql_autoincrement.asp

이제 귀하의 질문에 대해, 단일 테이블에 여러 auto_increment 열을 실제로 갖고 싶다면 그것을 모방해야합니다.

이것을 에뮬레이션해야하는 두 가지 이유 :

  1. MySQL은 PostgreSQL, Oracle, SQL Server 및 MS Access와 마찬가지로 테이블 당 하나의 증분 열만 수용합니다.
  2. MySQL에는 Oracle 및 PostgreSQL과 같은 SEQUENCE 스키마 객체가 없습니다.

그것을 어떻게 모방하겠습니까? ???

auto_increment 열이 하나만있는 여러 테이블을 사용하고 대상 테이블의 원하는 열에 매핑합니다. 예를 들면 다음과 같습니다.

이 예제를 복사하여 붙여 넣기 :

use test
DROP TABLE IF EXISTS teacher_popquizzes;
CREATE TABLE teacher_popquizzes
(
    teacher varchar(20) not null,
    class varchar(20) not null,
    pop_mon INT NOT NULL DEFAULT 0,
    pop_tue INT NOT NULL DEFAULT 0,
    pop_wed INT NOT NULL DEFAULT 0,
    pop_thu INT NOT NULL DEFAULT 0,
    pop_fri INT NOT NULL DEFAULT 0,
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
INSERT INTO teacher_popquizzes (teacher,class) VALUES
('mr jackson','literature'),
('mrs andrews','history'),
('miss carroll','spelling');
DROP TABLE IF EXISTS mon_seq;
DROP TABLE IF EXISTS tue_seq;
DROP TABLE IF EXISTS wed_seq;
DROP TABLE IF EXISTS thu_seq;
DROP TABLE IF EXISTS fri_seq;
CREATE TABLE mon_seq
(
    val INT NOT NULL DEFAULT 0,
    nextval INT NOT NULL DEFAULT 1,
    PRIMARY KEY (val)
);
CREATE TABLE tue_seq LIKE mon_seq;
CREATE TABLE wed_seq LIKE mon_seq;
CREATE TABLE thu_seq LIKE mon_seq;
CREATE TABLE fri_seq LIKE mon_seq;
BEGIN;
INSERT INTO tue_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;
SELECT nextval INTO @pop FROM mon_seq;
UPDATE teacher_popquizzes SET pop_tue = pop_tue + 1 WHERE id = 2;
COMMIT;
BEGIN;
INSERT INTO tue_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;
SELECT nextval INTO @pop FROM tue_seq;
UPDATE teacher_popquizzes SET pop_tue = pop_tue + 1 WHERE id = 1;
COMMIT;
BEGIN;
INSERT INTO wed_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;
SELECT nextval INTO @pop FROM wed_seq;
UPDATE teacher_popquizzes SET pop_wed = pop_wed + 1 WHERE id = 2;
COMMIT;
SELECT * FROM teacher_popquizzes;

교사를위한 팝 퀴즈 테이블이 생성됩니다. 또한 한 주에 하나씩 5 개의 시퀀스 에뮬레이터를 만들었습니다. 각 시퀀스 에뮬레이터는 val 열에 값 0을 삽입하여 작동합니다. 시퀀스 에뮬레이터가 비어 있으면 val 0, nextval 1로 시작합니다. 그렇지 않으면 nextval 열이 증가합니다. 그런 다음 시퀀스 에뮬레이터에서 nextval 열을 가져올 수 있습니다.

예제의 샘플 결과는 다음과 같습니다.

mysql> CREATE TABLE teacher_popquizzes
    -> (
    ->     teacher varchar(20) not null,
    ->     class varchar(20) not null,
    ->     pop_mon INT NOT NULL DEFAULT 0,
    ->     pop_tue INT NOT NULL DEFAULT 0,
    ->     pop_wed INT NOT NULL DEFAULT 0,
    ->     pop_thu INT NOT NULL DEFAULT 0,
    ->     pop_fri INT NOT NULL DEFAULT 0,
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
    -> );
Query OK, 0 rows affected (0.11 sec)

mysql> INSERT INTO teacher_popquizzes (teacher,class) VALUES
    -> ('mr jackson','literature'),
    -> ('mrs andrews','history'),
    -> ('miss carroll','spelling');
Query OK, 3 rows affected (0.03 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> DROP TABLE IF EXISTS mon_seq;
Query OK, 0 rows affected (0.06 sec)

mysql> DROP TABLE IF EXISTS tue_seq;
Query OK, 0 rows affected (0.03 sec)

mysql> DROP TABLE IF EXISTS wed_seq;
Query OK, 0 rows affected (0.03 sec)

mysql> DROP TABLE IF EXISTS thu_seq;
Query OK, 0 rows affected (0.05 sec)

mysql> DROP TABLE IF EXISTS fri_seq;
Query OK, 0 rows affected (0.07 sec)

mysql> CREATE TABLE mon_seq
    -> (
    ->     val INT NOT NULL DEFAULT 0,
    ->     nextval INT NOT NULL DEFAULT 1,
    ->     PRIMARY KEY (val)
    -> );
Query OK, 0 rows affected (0.12 sec)

mysql> CREATE TABLE tue_seq LIKE mon_seq;
Query OK, 0 rows affected (0.09 sec)

mysql> CREATE TABLE wed_seq LIKE mon_seq;
Query OK, 0 rows affected (0.08 sec)

mysql> CREATE TABLE thu_seq LIKE mon_seq;
Query OK, 0 rows affected (0.07 sec)

mysql> CREATE TABLE fri_seq LIKE mon_seq;
Query OK, 0 rows affected (0.14 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO tue_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT nextval INTO @pop FROM mon_seq;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> UPDATE teacher_popquizzes SET pop_tue = pop_tue + 1 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;
Query OK, 0 rows affected (0.03 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO tue_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;
Query OK, 2 rows affected (0.00 sec)

mysql> SELECT nextval INTO @pop FROM tue_seq;
Query OK, 1 row affected (0.00 sec)

mysql> UPDATE teacher_popquizzes SET pop_tue = pop_tue + 1 WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;
Query OK, 0 rows affected (0.03 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO wed_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT nextval INTO @pop FROM wed_seq;
Query OK, 1 row affected (0.00 sec)

mysql> UPDATE teacher_popquizzes SET pop_wed = pop_wed + 1 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;
Query OK, 0 rows affected (0.03 sec)

mysql> SELECT * FROM teacher_popquizzes;
+--------------+------------+---------+---------+---------+---------+---------+----+
| teacher      | class      | pop_mon | pop_tue | pop_wed | pop_thu | pop_fri | id |
+--------------+------------+---------+---------+---------+---------+---------+----+
| mr jackson   | literature |       0 |       1 |       0 |       0 |       0 |  1 |
| mrs andrews  | history    |       0 |       1 |       1 |       0 |       0 |  2 |
| miss carroll | spelling   |       0 |       0 |       0 |       0 |       0 |  3 |
+--------------+------------+---------+---------+---------+---------+---------+----+
3 rows in set (0.00 sec)

mysql>

MySQL에서 여러 개의 자동 증분 값이 실제로 필요한 경우이를 가장 유사한 방법으로 에뮬레이션 할 수 있습니다.

시도 해봐 !!!

업데이트 2011-06-23 21:05

내 예제에서 @pop 값을 사용하지 않는다는 것을 알았습니다.

이번에는 'pop_tue = pop_tue + 1'을 'pop_tue = @pop'으로 바꾸고 예제를 다시 시도했습니다.

mysql> use test
Database changed
mysql> DROP TABLE IF EXISTS teacher_popquizzes;
Query OK, 0 rows affected (0.05 sec)

mysql> CREATE TABLE teacher_popquizzes
    -> (
    ->     teacher varchar(20) not null,
    ->     class varchar(20) not null,
    ->     pop_mon INT NOT NULL DEFAULT 0,
    ->     pop_tue INT NOT NULL DEFAULT 0,
    ->     pop_wed INT NOT NULL DEFAULT 0,
    ->     pop_thu INT NOT NULL DEFAULT 0,
    ->     pop_fri INT NOT NULL DEFAULT 0,
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
    -> );
Query OK, 0 rows affected (0.06 sec)

mysql> INSERT INTO teacher_popquizzes (teacher,class) VALUES
    -> ('mr jackson','literature'),
    -> ('mrs andrews','history'),
    -> ('miss carroll','spelling');
Query OK, 3 rows affected (0.03 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> DROP TABLE IF EXISTS mon_seq;
Query OK, 0 rows affected (0.03 sec)

mysql> DROP TABLE IF EXISTS tue_seq;
Query OK, 0 rows affected (0.03 sec)

mysql> DROP TABLE IF EXISTS wed_seq;
Query OK, 0 rows affected (0.03 sec)

mysql> DROP TABLE IF EXISTS thu_seq;
Query OK, 0 rows affected (0.01 sec)

mysql> DROP TABLE IF EXISTS fri_seq;
Query OK, 0 rows affected (0.03 sec)

mysql> CREATE TABLE mon_seq
    -> (
    ->     val INT NOT NULL DEFAULT 0,
    ->     nextval INT NOT NULL DEFAULT 1,
    ->     PRIMARY KEY (val)
    -> );
Query OK, 0 rows affected (0.08 sec)

mysql> CREATE TABLE tue_seq LIKE mon_seq;
Query OK, 0 rows affected (0.09 sec)

mysql> CREATE TABLE wed_seq LIKE mon_seq;
Query OK, 0 rows affected (0.13 sec)

mysql> CREATE TABLE thu_seq LIKE mon_seq;
Query OK, 0 rows affected (0.11 sec)

mysql> CREATE TABLE fri_seq LIKE mon_seq;
Query OK, 0 rows affected (0.08 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO tue_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;

Query OK, 1 row affected (0.01 sec)

mysql> SELECT nextval INTO @pop FROM tue_seq;
Query OK, 1 row affected (0.00 sec)

mysql> UPDATE teacher_popquizzes SET pop_tue = @pop WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;
Query OK, 0 rows affected (0.03 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO tue_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;

Query OK, 2 rows affected (0.00 sec)

mysql> SELECT nextval INTO @pop FROM tue_seq;
Query OK, 1 row affected (0.00 sec)

mysql> UPDATE teacher_popquizzes SET pop_tue = @pop WHERE id = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;
Query OK, 0 rows affected (0.03 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO wed_seq (val) VALUES (0) ON DUPLICATE KEY UPDATE nextval = nextval + 1;

Query OK, 1 row affected (0.01 sec)

mysql> SELECT nextval INTO @pop FROM wed_seq;
Query OK, 1 row affected (0.00 sec)

mysql> UPDATE teacher_popquizzes SET pop_wed = @pop WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM teacher_popquizzes;
+--------------+------------+---------+---------+---------+---------+---------+----+
| teacher      | class      | pop_mon | pop_tue | pop_wed | pop_thu | pop_fri | id |
+--------------+------------+---------+---------+---------+---------+---------+----+
| mr jackson   | literature |       0 |       2 |       0 |       0 |       0 |  1 |
| mrs andrews  | history    |       0 |       1 |       1 |       0 |       0 |  2 |
| miss carroll | spelling   |       0 |       0 |       0 |       0 |       0 |  3 |
+--------------+------------+---------+---------+---------+---------+---------+----+
3 rows in set (0.00 sec)

mysql>

요약이 완전히 정확하지 않음 : PostgreSQL은 Oracle과 마찬가지로 여러 자동 증분 (직렬) 열을 지원합니다 (두 경우 모두 열의 값이 시퀀스로 채워짐). PostgreSQL은 또한 bigserial2,147,483,647보다 훨씬 큰 범위를 제공하는 데이터 유형을 제공합니다
a_horse_with_no_name

@a_horse_with_no_name : 감독해서 죄송합니다. 나는 여전히 postgresql의 여행사입니다. 나중에 답변을 업데이트하겠습니다. 나는 iPhone의 답을 찾고 있습니다. 좋은 하루 되세요!
RolandoMySQLDBA 2016 년

0

XL이 말했듯이 기본 키에만 국한되지 않습니다. 테이블 당 하나의 열만 가질 수 있다는 잠재적 인 제한이 있지만 가장 좋은 해결 방법은 다른 테이블에 필요한 수의 숫자를 생성 한 다음 필요한 곳에 삽입하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.