sql >> Base de Datos >  >> RDS >> PostgreSQL

postgresql genera secuencia sin espacio

Las secuencias no generan conjuntos de números sin espacios, y realmente no hay forma de hacer que lo hagan porque una reversión o un error "usarán" el número de secuencia.

Escribí un artículo sobre esto hace un tiempo. Está dirigido a Oracle, pero en realidad se trata de los principios fundamentales de los números sin espacios, y creo que lo mismo se aplica aquí.

Bueno, ha vuelto a pasar. Alguien ha preguntado cómo implementar un requisito para generar una serie de números sin brechas y un enjambre de detractores ha descendido sobre ellos para decir (y aquí lo parafraseo un poco) que esto matará el rendimiento del sistema, que rara vez es un requisito válido. , que quien escribió el requisito es un idiota, bla, bla, bla.

Como señalo en el hilo, a veces es un requisito legal genuino generar series de números sin espacios. Los números de factura de más de 2 000 000 de organizaciones en el Reino Unido que están registradas con IVA (impuesto sobre las ventas) tienen ese requisito, y la razón de esto es bastante obvia:hace que sea más difícil ocultar la generación de ingresos de las autoridades fiscales. He visto comentarios de que es un requisito en España y Portugal, y no me sorprendería que no lo fuera en muchos otros países.

Entonces, si aceptamos que es un requisito válido, ¿bajo qué circunstancias son un problema las series de números* libres de huecos? El pensamiento grupal a menudo le haría creer que siempre lo es, pero de hecho es solo un problema potencial en circunstancias muy particulares.

  1. La serie de números no debe tener espacios.
  2. Múltiples procesos crean las entidades a las que se asocia el número (por ejemplo, facturas).
  3. Los números deben generarse en el momento en que se crea la entidad.

Si se deben cumplir todos estos requisitos, entonces tiene un punto de serialización en su aplicación, y lo discutiremos en un momento.

Primero, hablemos de los métodos para implementar un requisito de serie de números si puede eliminar cualquiera de esos requisitos.

Si su serie de números puede tener lagunas (y tiene varios procesos que requieren la generación instantánea del número), utilice un objeto Oracle Sequence. Son de muy alto rendimiento y se han discutido muy bien las situaciones en las que se pueden esperar huecos. No es demasiado difícil minimizar la cantidad de números omitidos haciendo esfuerzos de diseño para minimizar la posibilidad de una falla en el proceso entre la generación del número y la confirmación de la transacción, si eso es importante.

Si no tiene varios procesos que crean las entidades (y necesita una serie de números sin interrupciones que deben generarse instantáneamente), como podría ser el caso con la generación de facturas por lotes, entonces ya tiene un punto de serialización. Eso en sí mismo puede no ser un problema y puede ser una forma eficiente de realizar la operación requerida. En este caso, generar los números sin espacios es bastante trivial. Puede leer el valor máximo actual y aplicar un valor incremental a cada entidad con una serie de técnicas. Por ejemplo, si está insertando un nuevo lote de facturas en su tabla de facturas desde una tabla de trabajo temporal, podría:

insert into
  invoices
    (
    invoice#,
    ...)
with curr as (
  select Coalesce(Max(invoice#)) max_invoice#
  from   invoices)
select
  curr.max_invoice#+rownum,
  ...
from
  tmp_invoice
  ...

Por supuesto, protegería su proceso para que solo se pueda ejecutar una instancia a la vez (probablemente con DBMS_Lock si está usando Oracle), y protegería el número de factura con una contraseña de clave única, y probablemente verificaría los valores faltantes con un código separado si realmente, realmente te importa.

Si no necesita la generación instantánea de los números (pero los necesita sin interrupciones y múltiples procesos generan las entidades), entonces puede permitir que se generen las entidades y se confirme la transacción, y luego dejar la generación del número a un solo lote trabajo. Una actualización en la tabla de entidades o una inserción en una tabla separada.

Entonces, ¿si necesitamos la trifecta de la generación instantánea de una serie de números sin espacios mediante múltiples procesos? Todo lo que podemos hacer es tratar de minimizar el período de serialización en el proceso, y ofrezco el siguiente consejo, y agradezco cualquier consejo adicional (o contraconsejo, por supuesto).

  1. Almacene sus valores actuales en una tabla dedicada. NO use una secuencia.
  2. Asegúrese de que todos los procesos utilicen el mismo código para generar nuevos números encapsulándolos en una función o procedimiento.
  3. Serialice el acceso al generador de números con DBMS_Lock, asegurándose de que cada serie tenga su propio bloqueo exclusivo.
  4. Mantenga el bloqueo en el generador de series hasta que se complete la transacción de creación de su entidad liberando el bloqueo en la confirmación
  5. Retrasar la generación del número hasta el último momento posible.
  6. Tenga en cuenta el impacto de un error inesperado después de generar el número y antes de que se complete la confirmación:¿revertirá la aplicación correctamente y liberará el bloqueo, o mantendrá el bloqueo en el generador de series hasta que la sesión se desconecte más tarde? Cualquiera que sea el método que se utilice, si la transacción falla, los números de serie deben "devolverse al grupo".
  7. ¿Puedes encapsular todo en un disparador en la mesa de la entidad? ¿Puede encapsularlo en una tabla u otra llamada API que inserte la fila y confirme la inserción automáticamente?

Artículo original