|
[필독] 처음 오시는 분을 위한 안내 (737) |
정은준1 |
2014-05 |
5235868 |
0 |
2014-05
5235868
1 정은준1
|
|
(광고) 단통법 시대의 인터넷가입 가이드(ver2.0) (234) |
백메가 |
2015-12 |
1761988 |
25 |
2015-12
1761988
1 백메가
|
65284 |
dell r730 vs dell r620 ? (2) |
바부팅이 |
2016-04 |
4048 |
0 |
2016-04
4048
1 바부팅이
|
65283 |
GMA 4500 리눅스 그래픽 가속이 되나요? |
딸기대장 |
2016-04 |
3726 |
0 |
2016-04
3726
1 딸기대장
|
65282 |
RAID 구성시 하드 혼용 (4) |
online9 |
2016-04 |
4818 |
0 |
2016-04
4818
1 online9
|
65281 |
[DELL] PowerEdge R220 서버 하드는 일반하드 장착 가능한가요??? (2) |
초보IT |
2016-04 |
4271 |
0 |
2016-04
4271
1 초보IT
|
65280 |
외국에 거주중인데 선거하는 방법이 없을까요? (2) |
황재광 |
2016-04 |
4357 |
0 |
2016-04
4357
1 황재광
|
65279 |
개인용 간이 경량 웹하드 어플 (2) |
전설속의미… |
2016-04 |
4371 |
1 |
2016-04
4371
1 전설속의미…
|
65278 |
공인중개사 시험이 많이 어렵나요? (6) |
김건우 |
2016-04 |
9881 |
1 |
2016-04
9881
1 김건우
|
65277 |
프로그래밍 하시는 분들께 질문 하나 드릴게요 .. (34) |
김제연 |
2016-03 |
14995 |
0 |
2016-03
14995
1 김제연
|
65276 |
부산 회원님들 여기가 어디인가요? (11) |
임현준 |
2016-03 |
4712 |
2 |
2016-03
4712
1 임현준
|
65275 |
CPU 선택 좀 도와주세요. (2) |
JK김동욱 |
2016-03 |
4805 |
0 |
2016-03
4805
1 JK김동욱
|
65274 |
OSX에서 공유 폴더 (8) |
DoWoo |
2016-03 |
4601 |
0 |
2016-03
4601
1 DoWoo
|
65273 |
저전압이 반도체를 망가뜨리는 이유가 궁금합니다. (30) |
isaiah |
2016-03 |
23559 |
2 |
2016-03
23559
1 isaiah
|
65272 |
[요청] MS Office2007 basic k 설치 파일을 구합니다. (3) |
누굴까 |
2016-03 |
4460 |
0 |
2016-03
4460
1 누굴까
|
65271 |
초보전산담당자가 궁금한점이 있습니다.(DB크기와 RAM 관계) (17) |
Power멘솔 |
2016-03 |
6431 |
0 |
2016-03
6431
1 Power멘솔
|
65270 |
NAS CPU 업그레이드 질문드립니다(QNAP TS-870) (4) |
SkyBase |
2016-03 |
9434 |
0 |
2016-03
9434
1 SkyBase
|
65269 |
한 컴퓨터에 레이드 컨트롤러를 2대 장착해서 써도 문제 없을까요? (5) |
VSPress |
2016-03 |
4042 |
1 |
2016-03
4042
1 VSPress
|
65268 |
주휴수당 연차수당 등등 문의 (6) |
2FluF |
2016-03 |
6295 |
0 |
2016-03
6295
1 2FluF
|
65267 |
영어 도움부탁드립니다.. (2) |
이사장 |
2016-03 |
3773 |
0 |
2016-03
3773
1 이사장
|
65266 |
정보통신 학원 추천해주세요 (8) |
미수맨 |
2016-03 |
4708 |
0 |
2016-03
4708
1 미수맨
|
65265 |
인텔 DDR3 775보드에서도 2G이상 메모리 지원안하나요?? (11) |
대전사람 |
2016-03 |
8732 |
0 |
2016-03
8732
1 대전사람
|
중복첵크()
저장()
아니면
저장()
{
중복첵크()
write...
}
황진우님 말씀대로 할 수도 있고, 그렇게 해야 하지만 이게 클라이언트에서 난수를 만들게 되면 중복값이 생성될 때마다 체크하고 충돌하면 다시 만들어야 하기 때문에
뒤로 갈수록 시간이 늘어나게 될 껍니다.
그래서...서버가 이미 만들어진 난수를 가지고 있다가 클라이언트의 요청이 있을때 그 난수를 던져주고, 사용했다고 체크하면 해결이 좀 더 용이하다고 생각됩니다.
음.......이것도 문제가 있기는 하군요,. ^.^;;
혼자 하는건 아무 문제가 없을듯한데 .. 여러 사람이 동시에 저장하면 문제가 될 소지가 있을것 같아서요.
어떤 면에선 DB 에 난수테이블을 하나 만들어서 미리 중복되지 않는 난수를 넣어놓고 하나씩 빼쓰는게 나을 수도 있습니다.
테스트 방법
두대의 컴퓨터를 옆에 두고 동시에 저장을 눌러보고 DB를 확인해보세요..
제가 microtime + 난수4자리 로 값을 db에 넣었다가 된통 당한적이 있었죠.
동시에 300명 정도가 write를 하니 1-2건 정도가 중복이 되더라구요.
무한루프에 빠지지 않게 처리하면 바로 에러처리가 되긴 하지만요.
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
8자리 숫자로 줄이면 중복 가능성이 생깁니다.
영어를 같이 쓰면 중복확율을 확 줄일 수가 있긴 한데 말입니다. (위에 쓰신 것처럼...36진수를 만들 수 있으니...대소문자 구분까지 넣으면 62진수를...쿨럭~)
이걸로 중복이 발생하는 경우는 거진 없는데요 한번 해보세요~
조금더 머리쓰신다면
위에 중복 체크 함수를 쓰셔서
유니크 값 들어가는 부분에
microtime 값 + 00001 순번 하셔서
디비에 해당 값이 있을경우 체크하는부분에다가
microtime% 형태로 검색하시면 더 빠를듯 합니다. 그럴경우 일부 구간만 검색할 수 있으니깐요
이미 댓글로 좋은 아이디어들이 많이 나왔네요.
시간을 이용한다 하셨는데 시간 + 아이피 또는 php세션값등도 조합하시면 중복가능성이 많이 줄어듭니다.
하지만 그렇다고 0%는 될 수 없기에 안전장치는 필수입니다.
그 방법 중
등록 전 생성된 값이 정말 유니크 한지 중복검사 하는 방식은
중복체크와 등록하는 부분이 임계구역으로 원자화 시키지 않으면 중복이 발생할 수 있습니다.
php에서 임계구역을 어떻게 설정하는지 모르겠으나
임계구역에 등록시 마다 중복체크 하면 아마 동시등록자 수가 많을수록 성능저하가 있을 수 있겠지요.
그리고 웹서버를 병렬로 운영시엔 php에서 임계구역 걸어봤자 소용 없고요.
그런면에서는 디비에 유니크 인덱스를 걸고 등록시 오류를 잡아서 재등록도 괜찮은 방법이고요
성능이 매우 중요한 경우엔 속편하게 미리 중복되지 않는 랜덤테이블을 미리 만들어 랜덤값들을 미리 등록해 놓고 뽑아쓰든 자동증가값으로 조인해서 쓰든 하는 방법도 있습니다. 성능은 더이상 빠를 수 없겠죠.
디비에 id값을 사용하시는데(물론 자동증가분으로 설정하셨을거고..) 또 다른 번호가 왜 필요하신지?? 난수 함수(랜덤함수)를 사용하신다고
하시는것 봐서는 그냥 중복만 안되게 구분하면 되는것 아닌가요? 그럼 이미 id값 설정 하신 필드에 자동증가를 시켜주시면 해결될듯 하는데
저희 프로그램도 유니크한 숫자값이 필요(저희는 년도 + 시리얼 5자리)해서 초창기에는 별도 테이블에 중복 체크용 데이터를 넣고 했는데
그냥 필드에 id값 설정해 놓고 다른 필드에서 년도 + id설정된 필드값을 추가로 넣는 방식으로 해결했습니다.
20년전 자료구조론과 운영체제론 공부하며 네트워크 관련 프로그램 작성시 동시입력부분 때문에 항상 머리 아파했던 부분인데 (그당시에는 오라클 빼고는 그렇게 성능좋은 디비프로그램도 없었고) 요즘은 데이터 베이스 프로그램들이 워낙 좋아 많이 편해진것 같습니다(프로그램 손뗀지 이제 10년 가까이 되네요)
아직 어떤 ID 값으로 들어갈지 모르거든요 삽입이라
ID 값은 그냥 자동으로 올라가게 되어있고 랜덤한건 저희가 관리 할 수 있는 번호를 부여하기 위해서
그렇게 하려고 합니다
저장하면서 생성된 id값 받아와서 사용하면 될듯한데...
id 필드값을 제외한 다른 데이터가 극히 두문 경우로 설혹 똑같다 해도 같은 데이터를 읽어온 후 화면에 표출하여 사용자가 선택할수 있는 방식이면 될것 같은데(저희가 사용하는 프로그램 방식)
어떤 용도로 사용되어지는 프로그램인지가가 중요하긴 하겠네요.
이건 어떨까요?
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을 보장하는지는 모르겠지만요.
어차피 일단 데이터베이스에 레코드가 들어가면 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도 필요없고, 위의 소개된 여러 트릭들에 비해 어렵지도 않고(?), 가볍고 좋네요.
링크 주신 방법 잠깐 봤는데...괜찮아 보입니다.
저도 자세히 읽어봐야겠습니다. 나중에 써먹을데가 있을 것 같네요.
감사합니다~ ^^
전 그냥 트리거로 처리하는데...
갑자기 중복이 생길까봐 걱정이 되네요..
이게 자리수가 길어질것 같으면 30진수 60진수 등으로 변환하는거죠 (그럼 바이트 확 주니까)
이럴경우 문자 들어가는건 감안하셔야하구요.
오직숫자로 해야하고 중복체크 안하려면 결국 시간으로 해야겠구요.(자연스러운 숫자처럼 보일려면 머리굴려서 구현을 하셔야겠죠)
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
기본적으로 MySQL에서 완벽한 방법이 없습니다.
그나마 현실적인 방법은 위의 분들이 말씀하신 방법 사용하시고 추가적으로 insert된 entry를 다시 확인해야 합니다.
앞의 prefix를 날짜로 하시면 됩니다.
꼭 랜덤한 값이 필요하면 현재시각와 일련번호 붙인 다음에 MD5로 한번 돌리던가 하세요.
위에서 언급된 것처럼 auto_increment로 만든 컬럼의 값(ID)을 아래의 함수를
이용하여 현재 세션의 insert에 할당된 값을 읽어 냅니다.
http://php.net/manual/kr/function.mysql-insert-id.php
insert 전에 값이 필요하다면 오라클의 sequence를 얻는 것처럼 auto_increment로
지정한 컬럼을 가진 테이블을 하나 생성해놓고 insert 하여 값을 얻은 후 delete
해 버리면 되겠죠 ?