복붙노트

[SQL] 대기열로 데이터베이스 테이블을 사용하여

SQL

대기열로 데이터베이스 테이블을 사용하여

나는 대기열로 데이터베이스 테이블을 사용하고 싶습니다. 나는 거기에 삽입하고 삽입 된 순서 (FIFO)에의 요소를 먹고 싶어. 나는 이러한 거래 수천 매 초마다 가지고 있기 때문에 내 주요 고려 사항은 성능이다. 그래서 전체 테이블을 검색하지 않고 나에게 첫 번째 요소를 제공하는 SQL 쿼리를 사용하고 싶습니다. 나는 그것을 읽을 때 나는 행을 제거하지 마십시오. 합니까 SELECT TOP 1 ..... 여기 도움이? 나는 특별한 인덱스를 사용해야합니까?

해결법

  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. ==============================

    2.당신이 처리 된 행을 제거하지 않으면, 당신은 행이 이미 처리 된 것을 나타내는 플래그의 일종을 필요로 할 것입니다.

    당신이 처리 된 행을 제거하지 않으면, 당신은 행이 이미 처리 된 것을 나타내는 플래그의 일종을 필요로 할 것입니다.

    그 플래그에 인덱스를 넣고 열 당신에 의해 주문 가고있다.

    디큐 트랜잭션이 쿼리를 막힘되지 않도록, 그 깃발 위에 테이블을 분할.

    당신이 정말로 1.000 메시지 초마다 얻을 것입니다 경우, 그 86.400.000 행 일이 발생할 것입니다. 당신은 오래된 행을 정리하는 몇 가지 방법을 생각 할 수 있습니다.

  3. ==============================

    3.모든 데이터베이스 엔진 / 구현에 따라 달라집니다.

    모든 데이터베이스 엔진 / 구현에 따라 달라집니다.

    다음과 같은 열이있는 테이블에 나 간단한 큐의 경우 :

    id / task / priority / date_added
    

    일반적으로 작동합니다.

    나는 그룹 작업에 우선 순위 및 작업을 사용하고 두 배로 작업의 경우에는 내가 더 큰 우선 순위를 choosed 할.

    그리고하지 걱정을 - 현대 데이터베이스 "수천"에 대한 아무것도 특별하다.

  4. ==============================

    4.이는 당신이 삽입물의 날짜를 추적 할 무언가를 사용하는 모든에서 어떤 문제가되지 않습니다. MySQL의 옵션을 보려면 여기를 참조하십시오. 문제는 당신이 오직 절대 가장 최근에 제출 된 항목이 필요한지 여부 또는 반복해야하는지 여부입니다. 당신은 반복해야하는 경우에, 당신이해야 할 일 성명을 통해 루프 BY 순서로 덩어리를 잡아, 당신은 당신이 당신의 다음 청크를 잡아 때 사용할 수 있도록 마지막 날짜를 기억합니다.

    이는 당신이 삽입물의 날짜를 추적 할 무언가를 사용하는 모든에서 어떤 문제가되지 않습니다. MySQL의 옵션을 보려면 여기를 참조하십시오. 문제는 당신이 오직 절대 가장 최근에 제출 된 항목이 필요한지 여부 또는 반복해야하는지 여부입니다. 당신은 반복해야하는 경우에, 당신이해야 할 일 성명을 통해 루프 BY 순서로 덩어리를 잡아, 당신은 당신이 당신의 다음 청크를 잡아 때 사용할 수 있도록 마지막 날짜를 기억합니다.

  5. ==============================

    5.아마도 단일 경기 후 반환을 강제로 ... 도움이 될 당신의 선택 문에 LIMIT = 1을 추가 ...

    아마도 단일 경기 후 반환을 강제로 ... 도움이 될 당신의 선택 문에 LIMIT = 1을 추가 ...

  6. ==============================

    6.당신은 테이블에서 레코드를 삭제하지 않기 때문에, 당신이 처리 (처리, ID)에 복합 인덱스가 필요하면 현재 레코드가 처리 된 경우 표시하는 열입니다.

    당신은 테이블에서 레코드를 삭제하지 않기 때문에, 당신이 처리 (처리, ID)에 복합 인덱스가 필요하면 현재 레코드가 처리 된 경우 표시하는 열입니다.

    가장 좋은 것은 기록을 위해 파티션 테이블을 생성하고 처리 분야 파티션 키하게 될 것이다. 이 방법을 사용하면 세 이상의 로컬 인덱스를 유지할 수 있습니다.

    당신은 항상 ID 순서로 레코드를 처리하고, 두 상태를 가질 경우, 기록을 갱신 단지 인덱스의 첫 번째 잎에서 기록을 복용하고 마지막 잎에 추가 의미

    현재 처리 기록은 항상 모든 처리되지 않은 레코드의 최소한 ID와 모든 처리 기록의 가장 큰 ID를 가질 것이다.

  7. ==============================

    7.날짜 (또는 자동 증가) 칼럼을 통해 클러스터 된 인덱스를 만듭니다. 이 대략 인덱스 순서에 테이블의 행을 유지하고 인덱스 컬럼에 의해 주문시 빠른 인덱스 기반 액세스를 허용합니다. (당신의 RDMBS에 따라, 또는 LIMIT X) TOP X를 사용하면 만 인덱스에서 첫 번째 X 항목을 검색합니다.

    날짜 (또는 자동 증가) 칼럼을 통해 클러스터 된 인덱스를 만듭니다. 이 대략 인덱스 순서에 테이블의 행을 유지하고 인덱스 컬럼에 의해 주문시 빠른 인덱스 기반 액세스를 허용합니다. (당신의 RDMBS에 따라, 또는 LIMIT X) TOP X를 사용하면 만 인덱스에서 첫 번째 X 항목을 검색합니다.

    성능 경고 : 당신은 항상 (실제 데이터에) 쿼리의 실행 계획을 검토해야 최적화 프로그램이 예상치 못한 일을하지 않는 것을 확인 할 수 있습니다. 또한 결정을 내릴 수 있도록 벤치 마크 (다시 실제 데이터에) 쿼리를 시도합니다.

  8. ==============================

    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. ==============================

    9.순서대로 이것에 대한 아주 쉬운 솔루션은 거래를하지, 잠금 장치 등은 변경 내용 추적 메커니즘 (안 데이터 캡처)를 사용하는 것입니다. 그것은 당신이 특정 버전 이후에 무슨 일이 있었 변경됩니다 무엇을 추적 할 수 있도록 각각의 추가 / 업데이트 / 삭제 행 버전 사용합니다.

    순서대로 이것에 대한 아주 쉬운 솔루션은 거래를하지, 잠금 장치 등은 변경 내용 추적 메커니즘 (안 데이터 캡처)를 사용하는 것입니다. 그것은 당신이 특정 버전 이후에 무슨 일이 있었 변경됩니다 무엇을 추적 할 수 있도록 각각의 추가 / 업데이트 / 삭제 행 버전 사용합니다.

    그래서, 당신은 마지막 버전 및 쿼리 새로운 변화를 지속.

    쿼리가 실패하면, 당신은 항상 돌아가서 마지막 버전에서 쿼리 데이터 수 있습니다. 당신은 하나 개의 쿼리로 모든 변경 사항을 얻을하려는 경우 또한, 당신은 마지막 버전으로 상위 N 순서를 얻고 난 당신이 다시 쿼리에 가지고 거라고 가장 큰 버전을 저장할 수 있습니다.

    2008 서버 SQL에서 변경 내용 추적을 사용하여 예를 들어이보기

  10. from https://stackoverflow.com/questions/2177880/using-a-database-table-as-a-queue by cc-by-sa and MIT license