[SQL] 대기열로 데이터베이스 테이블을 사용하여
SQL대기열로 데이터베이스 테이블을 사용하여
나는 대기열로 데이터베이스 테이블을 사용하고 싶습니다. 나는 거기에 삽입하고 삽입 된 순서 (FIFO)에의 요소를 먹고 싶어. 나는 이러한 거래 수천 매 초마다 가지고 있기 때문에 내 주요 고려 사항은 성능이다. 그래서 전체 테이블을 검색하지 않고 나에게 첫 번째 요소를 제공하는 SQL 쿼리를 사용하고 싶습니다. 나는 그것을 읽을 때 나는 행을 제거하지 마십시오. 합니까 SELECT TOP 1 ..... 여기 도움이? 나는 특별한 인덱스를 사용해야합니까?
해결법
-
==============================
1.나는 각 대기 항목에 대한 고유 증가 ID를 제공하기 위해 기본 키와 같은 IDENTITY 필드를 사용하고, 그 위에 클러스터 된 인덱스를 다루고 싶어요. 이 항목이 대기 된 순서를 나타낼 것이다.
나는 각 대기 항목에 대한 고유 증가 ID를 제공하기 위해 기본 키와 같은 IDENTITY 필드를 사용하고, 그 위에 클러스터 된 인덱스를 다루고 싶어요. 이 항목이 대기 된 순서를 나타낼 것이다.
당신이 그들을 처리하는 동안 큐 테이블의 항목을 유지하려면 (예를 들어, 0 = 1, 처리 2 =이 처리되는 = 대기) 특정 항목의 현재 상태를 나타 내기 위해 "상태"필드를 필요 했어. 이것은 항목이 두 번 처리 될 방지 할 필요가있다.
큐에서 항목을 처리 할 때, 테이블에 다음 항목이 아닌 현재 처리중인 찾아야 할 것입니다. 이 아래 있듯이 여러 프로세스가 동시에 처리 같은 항목을 따기 방지 할 수 있도록하는 방식으로 할 필요가있다. 당신이 큐를 구현할 때 반드시 알아야 할 테이블 힌트 UPDLOCK 및 READPAST을합니다.
예를 들면 sproc에 내,이 같은 :
DECLARE @NextID INTEGER BEGIN TRANSACTION -- Find the next queued item that is waiting to be processed SELECT TOP 1 @NextID = ID FROM MyQueueTable WITH (UPDLOCK, READPAST) WHERE StateField = 0 ORDER BY ID ASC -- if we've found one, mark it as being processed IF @NextId IS NOT NULL UPDATE MyQueueTable SET Status = 1 WHERE ID = @NextId COMMIT TRANSACTION -- If we've got an item from the queue, return to whatever is going to process it IF @NextId IS NOT NULL SELECT * FROM MyQueueTable WHERE ID = @NextID
항목이 실패 처리하면 나중에 다시 시도 할 수 하시겠습니까? 그렇다면, 당신은 0 또는 뭔가 상태 등을 다시 설정해야합니다. 즉 더 생각이 필요합니다.
그냥 믹스에 그것을 던져 줄 알았는데 - 또한, MSMQ와 같은 큐,하지만 무언가로 데이터베이스 테이블을 사용하지 마십시오!
-
==============================
2.당신이 처리 된 행을 제거하지 않으면, 당신은 행이 이미 처리 된 것을 나타내는 플래그의 일종을 필요로 할 것입니다.
당신이 처리 된 행을 제거하지 않으면, 당신은 행이 이미 처리 된 것을 나타내는 플래그의 일종을 필요로 할 것입니다.
그 플래그에 인덱스를 넣고 열 당신에 의해 주문 가고있다.
디큐 트랜잭션이 쿼리를 막힘되지 않도록, 그 깃발 위에 테이블을 분할.
당신이 정말로 1.000 메시지 초마다 얻을 것입니다 경우, 그 86.400.000 행 일이 발생할 것입니다. 당신은 오래된 행을 정리하는 몇 가지 방법을 생각 할 수 있습니다.
-
==============================
3.모든 데이터베이스 엔진 / 구현에 따라 달라집니다.
모든 데이터베이스 엔진 / 구현에 따라 달라집니다.
다음과 같은 열이있는 테이블에 나 간단한 큐의 경우 :
id / task / priority / date_added
일반적으로 작동합니다.
나는 그룹 작업에 우선 순위 및 작업을 사용하고 두 배로 작업의 경우에는 내가 더 큰 우선 순위를 choosed 할.
그리고하지 걱정을 - 현대 데이터베이스 "수천"에 대한 아무것도 특별하다.
-
==============================
4.이는 당신이 삽입물의 날짜를 추적 할 무언가를 사용하는 모든에서 어떤 문제가되지 않습니다. MySQL의 옵션을 보려면 여기를 참조하십시오. 문제는 당신이 오직 절대 가장 최근에 제출 된 항목이 필요한지 여부 또는 반복해야하는지 여부입니다. 당신은 반복해야하는 경우에, 당신이해야 할 일 성명을 통해 루프 BY 순서로 덩어리를 잡아, 당신은 당신이 당신의 다음 청크를 잡아 때 사용할 수 있도록 마지막 날짜를 기억합니다.
이는 당신이 삽입물의 날짜를 추적 할 무언가를 사용하는 모든에서 어떤 문제가되지 않습니다. MySQL의 옵션을 보려면 여기를 참조하십시오. 문제는 당신이 오직 절대 가장 최근에 제출 된 항목이 필요한지 여부 또는 반복해야하는지 여부입니다. 당신은 반복해야하는 경우에, 당신이해야 할 일 성명을 통해 루프 BY 순서로 덩어리를 잡아, 당신은 당신이 당신의 다음 청크를 잡아 때 사용할 수 있도록 마지막 날짜를 기억합니다.
-
==============================
5.아마도 단일 경기 후 반환을 강제로 ... 도움이 될 당신의 선택 문에 LIMIT = 1을 추가 ...
아마도 단일 경기 후 반환을 강제로 ... 도움이 될 당신의 선택 문에 LIMIT = 1을 추가 ...
-
==============================
6.당신은 테이블에서 레코드를 삭제하지 않기 때문에, 당신이 처리 (처리, ID)에 복합 인덱스가 필요하면 현재 레코드가 처리 된 경우 표시하는 열입니다.
당신은 테이블에서 레코드를 삭제하지 않기 때문에, 당신이 처리 (처리, ID)에 복합 인덱스가 필요하면 현재 레코드가 처리 된 경우 표시하는 열입니다.
가장 좋은 것은 기록을 위해 파티션 테이블을 생성하고 처리 분야 파티션 키하게 될 것이다. 이 방법을 사용하면 세 이상의 로컬 인덱스를 유지할 수 있습니다.
당신은 항상 ID 순서로 레코드를 처리하고, 두 상태를 가질 경우, 기록을 갱신 단지 인덱스의 첫 번째 잎에서 기록을 복용하고 마지막 잎에 추가 의미
현재 처리 기록은 항상 모든 처리되지 않은 레코드의 최소한 ID와 모든 처리 기록의 가장 큰 ID를 가질 것이다.
-
==============================
7.날짜 (또는 자동 증가) 칼럼을 통해 클러스터 된 인덱스를 만듭니다. 이 대략 인덱스 순서에 테이블의 행을 유지하고 인덱스 컬럼에 의해 주문시 빠른 인덱스 기반 액세스를 허용합니다. (당신의 RDMBS에 따라, 또는 LIMIT X) TOP X를 사용하면 만 인덱스에서 첫 번째 X 항목을 검색합니다.
날짜 (또는 자동 증가) 칼럼을 통해 클러스터 된 인덱스를 만듭니다. 이 대략 인덱스 순서에 테이블의 행을 유지하고 인덱스 컬럼에 의해 주문시 빠른 인덱스 기반 액세스를 허용합니다. (당신의 RDMBS에 따라, 또는 LIMIT X) TOP X를 사용하면 만 인덱스에서 첫 번째 X 항목을 검색합니다.
성능 경고 : 당신은 항상 (실제 데이터에) 쿼리의 실행 계획을 검토해야 최적화 프로그램이 예상치 못한 일을하지 않는 것을 확인 할 수 있습니다. 또한 결정을 내릴 수 있도록 벤치 마크 (다시 실제 데이터에) 쿼리를 시도합니다.
-
==============================
8.나는 "어떻게 큐에 테이블을 설정합니까"같은 일반적인 질문을했고 난 아무데도 원하는 답을 찾을 수 없습니다.
나는 "어떻게 큐에 테이블을 설정합니까"같은 일반적인 질문을했고 난 아무데도 원하는 답을 찾을 수 없습니다.
여기에 내가 더 잘 sqlite3를 노드 / SQLite는 / 대한 해낸 것입니다. 기본적으로 당신의 사용 사례에 대한 BY 절 내부 WHERE 및 ORDER를 수정합니다.
module.exports.pickBatchInstructions = (db, batchSize) => { const buf = crypto.randomBytes(8); // Create a unique batch identifier const q_pickBatch = ` UPDATE instructions SET status = '${status.INSTRUCTION_INPROGRESS}', run_id = '${buf.toString("hex")}', mdate = datetime(datetime(), 'localtime') WHERE id IN (SELECT id FROM instructions WHERE status is not '${status.INSTRUCTION_COMPLETE}' and run_id is null ORDER BY length(targetpath), id LIMIT ${batchSize}); `; db.run(q_pickBatch); // Change the status and set the run id const q_getInstructions = ` SELECT * FROM instructions WHERE run_id = '${buf.toString("hex")}' `; const rows = db.all(q_getInstructions); // Get all rows with this batch id return rows; };
-
==============================
9.순서대로 이것에 대한 아주 쉬운 솔루션은 거래를하지, 잠금 장치 등은 변경 내용 추적 메커니즘 (안 데이터 캡처)를 사용하는 것입니다. 그것은 당신이 특정 버전 이후에 무슨 일이 있었 변경됩니다 무엇을 추적 할 수 있도록 각각의 추가 / 업데이트 / 삭제 행 버전 사용합니다.
순서대로 이것에 대한 아주 쉬운 솔루션은 거래를하지, 잠금 장치 등은 변경 내용 추적 메커니즘 (안 데이터 캡처)를 사용하는 것입니다. 그것은 당신이 특정 버전 이후에 무슨 일이 있었 변경됩니다 무엇을 추적 할 수 있도록 각각의 추가 / 업데이트 / 삭제 행 버전 사용합니다.
그래서, 당신은 마지막 버전 및 쿼리 새로운 변화를 지속.
쿼리가 실패하면, 당신은 항상 돌아가서 마지막 버전에서 쿼리 데이터 수 있습니다. 당신은 하나 개의 쿼리로 모든 변경 사항을 얻을하려는 경우 또한, 당신은 마지막 버전으로 상위 N 순서를 얻고 난 당신이 다시 쿼리에 가지고 거라고 가장 큰 버전을 저장할 수 있습니다.
2008 서버 SQL에서 변경 내용 추적을 사용하여 예를 들어이보기
from https://stackoverflow.com/questions/2177880/using-a-database-table-as-a-queue by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] SQL 키워드에 대한 대문자를 사용하는 좋은 이유가 있나요? [닫은] (0) | 2020.06.01 |
---|---|
[SQL] 엔티티 프레임 워크에서 예외가 발생합니다 - 잘못된 개체 이름 'dbo.BaseCs' (0) | 2020.06.01 |
[SQL] PostgreSQL을 누적 총 개수 (0) | 2020.06.01 |
[SQL] 하나의 SQL 서버에서 다른 서버로 내보내기 테이블 데이터 (0) | 2020.05.31 |
[SQL] 는 SQL 서버에서 하위 쿼리를 사용하여 업데이트 쿼리 (0) | 2020.05.31 |