2009-04-30 3 views
10

InnoDB 스토리지 엔진과 트랜잭션과 함께 MySQL을 사용하고 있으며 문제가 발생했습니다 : MySQL에서 Oracle의 SEQUENCE를 에뮬레이트하는 좋은 방법이 필요합니다. 요구 사항은 다음과 같습니다 - 동시성 지원 - 트랜잭션 안전 - 값 중 일부는 사용하지 않을 경우 최대 성능 (의미 최소화 잠금 및 교착 상태)MySQL에서 트랜잭션 안전 시퀀스 에뮬레이트

우리는 순서 즉 간격이 확인되어, 상관 없어. 카운터를 사용하여 별도의 InnoDB 테이블을 생성하여 쉽게 달성 할 수있는 방법이 있지만 트랜잭션에 참여하고 잠금과 대기를 도입한다는 의미입니다. 수동 잠금, 다른 아이디어 또는 베스트 프랙티스로 MyISAM 테이블을 시험해보고 싶습니다.

답변

14

, 당신은 같은 N라는 이름의 시퀀스와 원자 순서 메커니즘을 만들 수 있습니다 이 : 당신은 '갑'에 대한 행이 가정

CREATE TABLE sequence (
    seq_name varchar(20) unique not null, 
    seq_current unsigned int not null 
); 

:

당신의 시퀀스를 저장하는 테이블을 만듭니다 테이블에서 다음과 같이 다음 시퀀스 ID를 원자 적으로 가져올 수 있습니다.

잠금이 필요하지 않습니다. 두 문장 모두 같은 세션에서 실행되어야하므로 Select가 발생할 때 로컬 변수 @next가 실제로 정의됩니다.

+0

감사합니다. 거의 모든 일을 처리 한 결과가 거의 정확합니다. –

+1

레코드가없는 경우이 쿼리를 사용하십시오. INSERT INTO sequence (seq_name, seq_current) VALUES ('foo', (@next : = 1)) 이중 키 ON 업데이트 seq_current = (@next : = seq_current + 1); 그러면 SELECT @next;를 호출한다. – iwat

+0

당신이 qu1j0t3의 대답 iwat의 의견을 결합 할 수 있습니다 : 'sequences2 (seq_name, seq_current) 값으로 INSERT ('foo는'LAST_INSERT_ID (1)) DUPLICATE KEY UPDATE seq_current = LAST_INSERT_ID ON (seq_current + 1);' 'SELECT LAST_INSERT_ID();'를 호출하거나 응용 프로그램 드라이버를 사용하는 경우 내장 자동 증가 호출을 사용하십시오 (예 : jdbc의'Statement # getGeneratedKeys') – Alden

0

테이블의 MySQL ID 열이이를 처리하지 않습니까?

table_name 테이블 ( ID INTEGER AUTO_INCREMENT PRIMARY KEY )

을 만들거나 당신은 다른 테이블에 삽입이 아닌 다른 무언가를 위해 그것을 사용하는 찾고 계십니까?

(SQL 대신) 절차 형 언어를 사용하여 작성하는 경우 다른 옵션은 단일 정수 (또는 긴 정수) 값과이를 잠근 저장 프로 시저를 포함하는 테이블을 만드는 것입니다 값을 반환하기 전에 값을 증가시키고 잠금을 해제합니다.

(주 -.이 오류가있는 경우 중복을받지의 기회를 극대화 - - 당신이 값을 반환하기 전에 항상 증가 또는 트랜잭션 전체를 감싸)

그런 다음 독립적이 부를 것이다 당신의 기본 삽입/업데이트 (호출 메커니즘에 의해 자동으로 생성 된 트랜잭션에 걸리지 않기 때문에) 매개 변수로 전달할 수 있습니다.

나머지 작업과 독립적이므로 빠른 시간 내에 잠금 문제를 방지해야합니다. 잠금으로 인한 오류가 발생했다고해도 (데이터베이스가 오버로드되지 않는 한 거의 발생하지 않음) 두 번째/세 번째 호출이라고 할 수 있습니다.

+0

감사합니다, 두 번째 방법은 내가 더 많거나 적은 생각했던 것을 아마 , 세부 사항은 많은 도움이됩니다. 이러한 테이블에 가장 적합한 스토리지 엔진에 대한 의견은 무엇입니까? –

+0

저는 실제로 MySQL을 잘 모릅니다. 따라서 SQL Server에서이 작업을 수행 할 것을 권고 할 수는 없습니다. 내가 말하고자하는 것은 그것이 복잡하다고 생각하지 않는다는 것입니다. 그래서 최선의 접근법은 당신이 나머지 것들에 사용하는 것을 사용하고 복잡성을 줄이는 것이 될 것입니다. –

9

이 작업을 수행하는 올바른 방법은 MySQL manual에 나와있다 :

자동 증가는 사용자의 요구에 충분하지 않은 경우
UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1); 
SELECT LAST_INSERT_ID(); 
+1

여기 논리를 보지 못했습니다. 'LAST_INSERT_ID'는 자동 증가 필드에만 의미가 있습니다. 그러나 이미 자동으로 증가하는 경우 수동으로 증가시켜야하는 이유는 무엇입니까? – devios1

+0

수동으로 설정하지 않은 경우 LAST_INSERT_ID에 update 문이 적용되지 않습니다. 별도의 사용자 정의 변수를 사용하지 않고 업데이트 문에서 데이터를 가져 오는 트릭으로 사용할 수 있습니다. –

+0

이 접근법은 정확하며 @devios 주석은 오해의 소지가 있습니다. 'LAST_INSERT_ID (expr)'는 자동 증가와 아무 관련이 없습니다. – baf

4

우리는 높은 거래 게임 회사이며 우리의 요구에 맞는 이러한 종류의 솔루션이 필요합니다. 오라클 시퀀스의 기능 중 하나는 또한 설정할 수있는 증가 값이었습니다.

이 솔루션은 DUPLICATE KEY을 사용합니다.는 A 저장 프로 시저 또는 함수 sp_seq_next_val(VARCHAR)으로 다음

추상 :

CREATE TABLE sequences (
    id BIGINT DEFAULT 1, 
    name CHAR(20), 
    increment TINYINT, 
    UNIQUE KEY(name) 
); 

다음 인덱스를 얻으려면

INSERT INTO sequences (name) VALUES ("user_id") ON DUPLICATE KEY UPDATE id = id + increment;<br/> 
SELECT id FROM sequences WHERE name = "user_id"; 
+0

흥미로운 점은 포인터에 대한 감사입니다. ON DUPLICATE KEY는 항상 MySQL에서 INSERT로 원자 적입니까? –

+0

@Michael : 예, ON DUPLICATE KEY는 원자입니다. – kopos

관련 문제