Using a database table as a queue

前端 未结 9 2197
既然无缘
既然无缘 2020-12-02 07:45

I want to use a database table as a queue. I want to insert in it and take elements from it in the inserted order (FIFO). My main consideration is performance because I have

相关标签:
9条回答
  • 2020-12-02 08:19

    I had the same general question of "how do I turn a table into a queue" and couldn't find the answer I wanted anywhere.

    Here is what I came up with for Node/SQLite/better-sqlite3. Basically just modify the inner WHERE and ORDER BY clauses for your use case.

    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;
    };
    
    0 讨论(0)
  • 2020-12-02 08:30

    Since you don't delete the records from the table, you need to have a composite index on (processed, id), where processed is the column that indicates if the current record had been processed.

    The best thing would be creating a partitioned table for your records and make the PROCESSED field the partitioning key. This way, you can keep three or more local indexes.

    However, if you always process the records in id order, and have only two states, updating the record would mean just taking the record from the first leaf of the index and appending it to the last leaf

    The currently processed record would always have the least id of all unprocessed records and the greatest id of all processed records.

    0 讨论(0)
  • 2020-12-02 08:34

    Everything depends on your database engine/implementation.

    For me simple queues on tables with following columns:

    id / task / priority / date_added
    

    usually works.

    I used priority and task to group tasks and in case of doubled task i choosed the one with bigger priority.

    And don't worry - for modern databases "thousands" is nothing special.

    0 讨论(0)
  • 2020-12-02 08:34

    perhaps adding a LIMIT=1 to your select statement would help ... forcing the return after a single match...

    0 讨论(0)
  • 2020-12-02 08:39

    This will not be any trouble at all as long as you use something to keep track of the datetime of the insert. See here for the mysql options. The question is whether you only ever need the absolute most recently submitted item or whether you need to iterate. If you need to iterate, then what you need to do is grab a chunk with an ORDER BY statement, loop through, and remember the last datetime so that you can use that when you grab your next chunk.

    0 讨论(0)
  • 2020-12-02 08:39

    A very easy solution for this in order not to have transactions, locks etc is to use the change tracking mechanisms (not data capture). It utilizes versioning for each added/updated/removed row so you can track what changes happened after a specific version.

    So, you persist the last version and query the new changes.

    If a query fails, you can always go back and query data from the last version. Also, if you want to not get all changes with one query, you can get top n order by last version and store the greatest version I'd you have got to query again.

    See this for example Using Change Tracking in SQL Server 2008

    0 讨论(0)
提交回复
热议问题