프로그래밍 하시는 분들께 질문 하나 드릴게요 ..

김제연   
   조회 14994   추천 0    

프로그램을 하나 만들고 있는게 있는데요 


디비에 값을 넣는 프로그램인데 id 값이 있고 그 외에 .. 번호를 중복되지 않게 자동으로 생성해서

테이블에 넣어야 하는데 .. 생성해서 넣는건 문제가 안되는데 중복이 문제가 되네요 .. 


만약 제가 3000건을 입력할때... 랜덤으로 난수를 발생시켜서 저장하는데 

또 다른 사람이 접속해서 .. 같이 저장할경우에 랜덤 함수는 시간으로 하는거라 같은 값이

저장될 수도 있지 않나 싶어서요 .. 


질문드리고 싶은건.. 저희가 다중 사용자가 사용하는 상황에서 중복되지 않는 8자리를 만들어야 하는데 

지금은 시간을 가지고 만드는데 .. 이렇게 안하고 뭔가 다른 방법이 있을까 해서 문의드립니다.

여러 사람이 동시에 입력해도 중복되지 않는 난수를 발생 할 수 있는 방법이 있으시면 조언 부탁 드릴게요 .. 


짧은글 일수록 신중하게.
딸기대장 2016-03
오라클에선 sequence 로 처리합니다.
저장 함수 앞에 중복 첵크 하시면 중복이 작아집니다..

중복첵크()
저장()

아니면

저장()
{
 중복첵크()
 write...
}
     
강영준2C 2016-03
오 좋은생각인 것 같습니다 하하...
개발언어와 DB 종류를 알려주세요.
     
김제연 2016-04
php7 이고 mariadb 10.11입니다.
ZSNET5 2016-03
클라이언트에서 난수를 만드는게 아니고, 서버에서 난수를 만들어서 클라이언트가 그 값을 받아가게 하면 중복되지 않게 프로그래밍하기가 편할 것 같습니다.
황진우님 말씀대로 할 수도 있고, 그렇게 해야 하지만 이게 클라이언트에서 난수를 만들게 되면 중복값이 생성될 때마다 체크하고 충돌하면 다시 만들어야 하기 때문에
뒤로 갈수록 시간이 늘어나게 될 껍니다.
그래서...서버가 이미 만들어진 난수를 가지고 있다가 클라이언트의 요청이 있을때 그 난수를 던져주고, 사용했다고 체크하면 해결이 좀 더 용이하다고 생각됩니다.
음.......이것도 문제가 있기는 하군요,. ^.^;;
     
김제연 2016-04
네 .. 그냥 클라이언트에서 저장할 값만 서버로 날려주면 서버쪽에서 .. 난수를 발생시켜서 더해서 저장하고 있는데
혼자 하는건 아무 문제가 없을듯한데 .. 여러 사람이 동시에 저장하면 문제가 될 소지가 있을것 같아서요.
프로그램에서 난수를 만드는 건...DB 단에서 중복 체크를 하지 않으면 중복을 피할 길이 없습니다. (100% 중복이 난다기 보다는..중복이 날 확율이 있습니다).
어떤 면에선 DB 에 난수테이블을 하나 만들어서 미리 중복되지 않는 난수를 넣어놓고 하나씩 빼쓰는게 나을 수도 있습니다.
생각보다 중복입력이 잘안됩니다.
테스트 방법
두대의 컴퓨터를 옆에 두고 동시에 저장을 눌러보고 DB를 확인해보세요..
     
중복 잘 안난다고 하기에는...8자리면 좀 짧아요...12자리만 되어도 별로 걱정 안해도 될 것 같은데요...흐음...
          
ITES 2016-04
12자리도 피할수 없더라구요.
제가 microtime + 난수4자리  로 값을 db에 넣었다가 된통 당한적이 있었죠.
동시에 300명 정도가 write를 하니 1-2건 정도가 중복이 되더라구요.
성연 2016-04
중복체크하면 번거로우니까 필드에 유니크 속성을 넣고 인서트시 에러 발생하면 값을 바꿔서 다시 넣는건 어떨까요..
     
viper9 2016-04
무한루프에 빠질 우려가 있죠.

무한루프에 빠지지 않게 처리하면 바로 에러처리가 되긴 하지만요.
돌기름 2016-04
꼭 수가 아니어도 상관이 없다면 uuid 를 이용해보는것도 있습니다.
https://ko.wikipedia.org/wiki/%EB%B2%94%EC%9A%A9_%EA%B3%A0%EC%9C%A0_%EC%8B%9D%EB%B3%84%EC%9E%90
뭐 길이가 기니깐 짧게 줄이는 방법으로는
<?php

function uniqid_base36($more_entropy=false) {
    $s = uniqid('', $more_entropy);
    if (!$more_entropy)
        return base_convert($s, 16, 36);
       
    $hex = substr($s, 0, 13);
    $dec = $s[13] . substr($s, 15); // skip the dot
    return base_convert($hex, 16, 36) . base_convert($dec, 10, 36);
}

echo uniqid_base36() . "\n"; // eb98xzzhq7
echo uniqid_base36(true) . "\n"; // eb98xzzhr8dervre


출처 : http://php.net/manual/kr/function.uniqid.php
     
uuid 도 time 베이스입니다.
8자리 숫자로 줄이면 중복 가능성이 생깁니다.
영어를 같이 쓰면 중복확율을 확 줄일 수가 있긴 한데 말입니다. (위에 쓰신 것처럼...36진수를 만들 수 있으니...대소문자 구분까지 넣으면 62진수를...쿨럭~)
강한구 2016-04
microtime() 함수는 현재 시점의 Unix timestamp를  microseconds로 반환합니다.
이걸로 중복이 발생하는 경우는 거진 없는데요 한번 해보세요~

조금더 머리쓰신다면

위에 중복 체크 함수를 쓰셔서

유니크 값 들어가는 부분에
microtime 값 + 00001 순번 하셔서
디비에 해당 값이 있을경우 체크하는부분에다가
microtime% 형태로 검색하시면 더 빠를듯 합니다. 그럴경우 일부 구간만 검색할 수 있으니깐요
캔위드 2016-04
개발쪽 하신다면 아시겠지만 방법은 무궁무진 합니다.
이미 댓글로 좋은 아이디어들이 많이 나왔네요.

시간을 이용한다 하셨는데 시간 + 아이피 또는 php세션값등도 조합하시면 중복가능성이 많이 줄어듭니다.
하지만 그렇다고 0%는 될 수 없기에 안전장치는 필수입니다.

그 방법 중
등록 전 생성된 값이 정말 유니크 한지 중복검사 하는 방식은
중복체크와 등록하는 부분이 임계구역으로 원자화 시키지 않으면 중복이 발생할 수 있습니다.

php에서 임계구역을 어떻게 설정하는지 모르겠으나
임계구역에 등록시 마다 중복체크 하면 아마 동시등록자 수가 많을수록 성능저하가 있을 수 있겠지요.

그리고 웹서버를 병렬로 운영시엔 php에서 임계구역 걸어봤자 소용 없고요.

그런면에서는 디비에 유니크 인덱스를 걸고 등록시 오류를 잡아서 재등록도 괜찮은 방법이고요
성능이 매우 중요한 경우엔 속편하게 미리 중복되지 않는 랜덤테이블을 미리 만들어 랜덤값들을 미리 등록해 놓고 뽑아쓰든 자동증가값으로 조인해서 쓰든 하는 방법도 있습니다. 성능은 더이상 빠를 수 없겠죠.
양철괭이 2016-04
디비에 값을 넣는 프로그램인데 id 값이 있고 그 외에 .. 번호를 중복되지 않게 자동으로 생성해서 <--- 이 글에서
디비에 id값을 사용하시는데(물론 자동증가분으로 설정하셨을거고..)  또 다른 번호가 왜 필요하신지??  난수 함수(랜덤함수)를 사용하신다고
하시는것 봐서는 그냥 중복만 안되게 구분하면 되는것 아닌가요? 그럼 이미 id값 설정 하신 필드에 자동증가를 시켜주시면 해결될듯 하는데

저희 프로그램도 유니크한 숫자값이 필요(저희는 년도 + 시리얼 5자리)해서 초창기에는 별도 테이블에 중복 체크용 데이터를 넣고 했는데
그냥 필드에 id값 설정해 놓고 다른 필드에서 년도 + id설정된 필드값을 추가로 넣는 방식으로 해결했습니다.

20년전 자료구조론과 운영체제론 공부하며  네트워크 관련 프로그램 작성시 동시입력부분 때문에 항상 머리 아파했던 부분인데 (그당시에는 오라클 빼고는 그렇게 성능좋은 디비프로그램도 없었고) 요즘은 데이터 베이스 프로그램들이 워낙 좋아 많이 편해진것 같습니다(프로그램 손뗀지 이제 10년 가까이 되네요)
     
김제연 2016-04
등록당시기 때문에 입력전이라 ID 값이 아직 생성되지 않지 않나요?
아직 어떤 ID 값으로 들어갈지 모르거든요 삽입이라

ID 값은 그냥 자동으로 올라가게 되어있고 랜덤한건 저희가 관리 할 수 있는 번호를 부여하기 위해서
그렇게 하려고 합니다
          
박인호 2016-04
랜덤한데 관리가 되나요?
저장하면서 생성된 id값 받아와서 사용하면 될듯한데...
          
양철괭이 2016-04
id값은 자동증가하여 어떤값이 들어갈지 모르겠지만 삽입작업이 끝난후에는 바로 확인이 가능하니 다른작업시에는 그 값을 바로 읽어올수 있지 않나요?
id 필드값을 제외한 다른 데이터가 극히 두문 경우로 설혹 똑같다 해도 같은 데이터를 읽어온 후 화면에 표출하여 사용자가 선택할수 있는 방식이면 될것 같은데(저희가 사용하는 프로그램 방식)

어떤 용도로 사용되어지는 프로그램인지가가 중요하긴 하겠네요.
PiPPuuP 2016-04
으음..... vertx같은 형태이면 난수생성기를 싱글스레드서비스로 만들면 되기는 하는데....
이건 어떨까요?

unix_time ^ device_id

php랑 연동할 수 있는 싱글스레드 난수생성 서비스를 찾아보시는것도 좋을듯 합니다.

아니면 직접 만드시는것도 좋죠.

구조가
 queue
 rtable
 rthread
이렇게 되어있고
난수요청이 들어오면 queue에 request를 inqueue
rthread에서는 queue를 dequeue하면서 난수를 보내주는거죠.
rtable은 겹치지 않는 난수입니다.
처리기가 싱글스레드이니 만큼 최소한의 병목으로 unique를 보장할 수 있습니다.
문제는 sync인데 enqueue에서 발생하고, thread가 dequeue를 할 때 발생합니다.
rthread
  run
    while(true)
      lock (queue)
          while (queue is not empty)
            request = queue.dequeue()
            request ( rtable.next() )
          next
      unlock
    next
end

receive_request (request)
    lock (queue)
      queue.enqueue(request)
    unlock (queue)
end

이런식으로 두 군데가 queue를 가지고 경쟁합니다.


랜덤 생성도 좋지만, 성능을 위해서 난수인거같은 겹치지 않는 8자리 숫자를 나열하는 함수도 괜찬을겁니다. 이 경우에는 구조가 간결해지고 기억해야할건 다음 순번뿐이죠( http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/ ). 이렇게 구현할 경우 java로 구현한다면 queue이건 rthread이건 다 때려치우고 atomic을 보장하는 순번 하나로 해결되기도 합니다.
PHP 에도 Atomic integer 라이브러리가 있군요.
https://github.com/bmatheny/code-snippets/blob/master/php/AtomicInteger.php
이게 http request 트랜잭션간 atomic을 보장하는지는 모르겠지만요.
     
김제연 2016-04
이건 본것도 안본것도 아니네요 .. 쌩 초보인데 ㅜㅜ
          
PiPPuuP 2016-04
좀더 생각을 단순화 해보니, 서비스까지 갈 것도 없네요.

어차피 일단 데이터베이스에 레코드가 들어가면 unique id가 할당 되었을 테니 그다음에 이걸 기초로 like randomic sequencial unique number function을 통해 할당해주는 것이 좋은 방법일듯 합니다.
http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/
이걸 php로 구현한 다음, insert 레코드 이후, 해당 레코드의 id를 이용해서 8자리 유니크 아이디를 생성하는거죠.
좀 쉽게 설명하자면 record_id -> 무작위처럼 보이는 아이디로 매핑하는겁니다.
위 링크의 함수 프로토타입이 unsigned int permuteQPR(unsigned int x) 이렇게 되어있는데,
parameter x를 레코드 id로 넣는겁니다.
그러면 random(하게 보이는) unique id 생성!

그러니깐, request > insert > get latest inserted record_id > convert record_id to my_id > update (my_id) > response
이런 형태로 트렌잭션을 짜면 됩니다.
id 겹치는거 체크할 필요도 없습니다.
따라서 병목을 최소화 할 수 있지요.

8자리 hex number로 구성하신다면 매우매우 편리해질겁니다.
0123456789ABCDEF
로 구성되는거죠.
00000000 - FFFFFFFF(4294967295) 까지 4294967296(2^32: 32bits)개의 id를 만들 수 있습니다.

숫자로만 구성된다면 unique 아이디는
0-67108863(2^26: 26bits)
까지 가능하겠네요.
8자리를 만들기 위한 트릭으로
32891136 + (0-67108863) 로 구성하는것도 되겠고요.
이 경우 가능한 unique id 범위로는 32891136 - 99999999 이겠습니다.
앞의 padding숫자를 10000000 - 32891136 사이에서 자유로이 잡아도 되고...

unique id를 위한 싱글스레드 서비스도 필요없고, time도 필요없고, 위의 소개된 여러 트릭들에 비해 어렵지도 않고(?), 가볍고 좋네요.
               
저도 싱글쓰레드 난수 생성기를 댓글로 적어드리려다가...php 개발하시는 분들이 하시기에는 무리가 따를 것 같아서...패스했었네요. ;;;;
링크 주신 방법 잠깐 봤는데...괜찮아 보입니다.
저도 자세히 읽어봐야겠습니다. 나중에 써먹을데가 있을 것 같네요.
감사합니다~ ^^
포올 2016-04
와우~~ 방법이 많긴 하네요..
전 그냥 트리거로 처리하는데...
갑자기 중복이 생길까봐 걱정이 되네요..
씨형 2016-04
결국은 시간으로 하는게 장땡입니다 (중복체크 안하려면)
이게 자리수가 길어질것 같으면 30진수 60진수 등으로 변환하는거죠 (그럼 바이트 확 주니까)
이럴경우 문자 들어가는건 감안하셔야하구요.
오직숫자로 해야하고 중복체크 안하려면 결국 시간으로 해야겠구요.(자연스러운 숫자처럼 보일려면 머리굴려서 구현을 하셔야겠죠)
엠브리오 2016-04
대부분의 DB에서는 데이터의 중복입력을 방지하기 위한 방법을 가지고 있습니다.

http://kb.globalsoft.co.kr/web/web_view.php?notice_no=183

MySQL(maria db) 에서는 값을 자동으로 증가시켜 주는 auto_increment 와 primary key를 같이 쓰도록 되어 있네요.

http://blog.daum.net/question0921/539
epowergate 2016-04
여러의견 주셨는데 어떠한 방법이라도 DB에서 transaction/rowlock 등 지원하지 않으면 모두 허당입니다.
기본적으로 MySQL에서 완벽한 방법이 없습니다.
그나마 현실적인 방법은 위의 분들이 말씀하신 방법 사용하시고 추가적으로 insert된 entry를 다시 확인해야 합니다.
지노진호 2016-04
mariadb or mysql 에는 auto increment 항목을 지정할 수 있습니다.
     
지노진호 2016-04
위에위에 답글이 있네요.
회원K 2016-04
http://php.net/manual/en/function.uniqid.php ... php에서 unique를 쓰시고
앞의 prefix를 날짜로 하시면 됩니다.
viper9 2016-04
꼭 랜덤한 값이 필요한게 아니라면 오토인크리먼트 쓰시는게 맞구요.

꼭 랜덤한 값이 필요하면 현재시각와 일련번호 붙인 다음에 MD5로 한번 돌리던가 하세요.
오프라인 2016-04
mariadb에 insert 전에 필히 unique 값을 알아야만 하는 것이 아니라면
위에서 언급된 것처럼 auto_increment로 만든 컬럼의 값(ID)을 아래의 함수를
이용하여 현재 세션의 insert에 할당된 값을 읽어 냅니다.

http://php.net/manual/kr/function.mysql-insert-id.php

insert 전에 값이 필요하다면 오라클의 sequence를 얻는 것처럼 auto_increment로
지정한 컬럼을 가진 테이블을 하나 생성해놓고 insert 하여 값을 얻은 후 delete
해 버리면 되겠죠 ?


QnA
제목Page 2460/5724
2014-05   5235868   정은준1
2015-12   1761988   백메가
2016-04   4048   바부팅이
2016-04   3726   딸기대장
2016-04   4818   online9
2016-04   4271   초보IT
2016-04   4357   황재광
2016-04   4371   전설속의미…
2016-04   9881   김건우
2016-03   14995   김제연
2016-03   4712   임현준
2016-03   4805   JK김동욱
2016-03   4601   DoWoo
2016-03   23559   isaiah
2016-03   4460   누굴까
2016-03   6431   Power멘솔
2016-03   9434   SkyBase
2016-03   4042   VSPress
2016-03   6295   2FluF
2016-03   3773   이사장
2016-03   4708   미수맨
2016-03   8732   대전사람