2013-09-25 81 views
5

Tôi phải/phải tạo ID duy nhất cho hóa đơn. Tôi có một id bảng và một cột khác cho số duy nhất này. Tôi sử dụng mức cô lập tuần tự hóa. Sử dụngchuỗi postgresql tạo ra không có khoảng cách

var seq = @"SELECT invoice_serial + 1 FROM invoice WHERE ""type""[email protected] ORDER BY invoice_serial DESC LIMIT 1"; 

Không được giúp vì thậm chí sử dụng CẬP NHẬT nó sẽ không đọc giá trị chính xác như ở cấp độ tuần tự.

Chỉ có giải pháp dường như đặt một số mã thử lại.

+0

Có nhiều giải pháp phức tạp cho một chuỗi Gapless. Nhưng nếu bạn muốn nó đơn giản và chính xác, hãy thực hiện nó trong khối 'try', kiểm tra một ngoại lệ vi phạm chính và thử lại. [Câu trả lời của tôi ở đây] (http://stackoverflow.com/a/16465158/131874). –

+0

Xem thêm http://stackoverflow.com/questions/9984196/rails-postgres-does-not-re-use-deleted-ids-but-mysql-does/ – IMSoP

+0

Bản sao có thể có của [Khoảng trống giữa id khóa chính trong bảng sql ] (http://stackoverflow.com/questions/39099905/gaps-between-primary-key-id-in-sql-table) – e4c5

Trả lời

1

Bạn có thể tạo chuỗi không có bộ nhớ cache, sau đó nhận giá trị tiếp theo từ chuỗi và sử dụng làm bộ đếm của bạn.

CREATE SEQUENCE invoice_serial_seq START 101 CACHE 1; 
SELECT nextval('invoice_serial_seq'); 

Thông tin thêm here

+0

Điều này sẽ không đảm bảo trình tự thiếu khoảng cách vì những lý do người khác đã chỉ ra: rõ ràng nhất , hai giao dịch có thể yêu cầu ID, nhưng một giao dịch được khôi phục và do đó không sử dụng ID, để lại một khoảng trống trong chuỗi được chèn vào. – IMSoP

+2

Trong khi bạn nói đúng rằng một rollback có thể tạo ra một khoảng trống, điều này có thể tránh được bằng cách lấy id trình tự và chèn nó trong một giao dịch mà trong trường hợp bình thường sẽ không rollback. Ví dụ: tạo hóa đơn, tôi sẽ chèn bản ghi hóa đơn, thực hiện tất cả các thay đổi về hàng tồn kho và kế toán, THEN yêu cầu số hóa đơn và cập nhật hồ sơ hóa đơn với id hóa đơn (bảng hóa đơn có PK nội bộ riêng biệt). –

+0

@ Andres Olarte - đó là một suy nghĩ tốt! có vẻ đơn giản nhất để đạt được – murison

2

Bạn có thể khóa bảng để chèn, và/hoặc cần phải có mã retry. Không có tùy chọn nào khác. Nếu bạn dừng lại để suy nghĩ về những gì có thể xảy ra với:

  1. quá trình song song lăn lại
  2. khóa thời gian ra

bạn sẽ thấy lý do tại sao.

17

Trình tự không tạo các bộ số khoảng trống, và thực sự không có cách nào khiến chúng làm điều đó vì một cuộn ngược hoặc lỗi sẽ "sử dụng" số thứ tự.

Tôi đã viết một bài viết về điều này một thời gian trước đây. Nó hướng đến Oracle nhưng thực sự là về các nguyên tắc cơ bản của các số khoảng trống, và tôi nghĩ điều tương tự cũng áp dụng ở đây.

Vâng, điều đó lại xảy ra. Ai đó có asked cách thực hiện một yêu cầu để tạo ra một chuỗi số không có khoảng trống và một số người nói trên đã nói lên (và ở đây tôi diễn giải một chút) rằng điều này sẽ giết hiệu năng hệ thống, điều đó hiếm khi là yêu cầu hợp lệ , bất cứ ai viết yêu cầu là một kẻ ngốc blah blah blah.

Khi tôi chỉ ra chủ đề, đôi khi đó là yêu cầu pháp lý chính hãng để tạo chuỗi số liệu không có khoảng trống. Số hóa đơn cho hơn 2.000.000 tổ chức ở Vương quốc Anh là VAT (thuế bán hàng) đã đăng ký có yêu cầu như vậy và lý do cho điều này khá rõ ràng: khiến việc ẩn doanh thu từ cơ quan thuế trở nên khó khăn hơn. Tôi đã thấy nhận xét rằng đó là một yêu cầu ở Tây Ban Nha và Bồ Đào Nha, và tôi sẽ không ngạc nhiên nếu nó không phải là một yêu cầu ở nhiều quốc gia khác.

Vì vậy, nếu chúng tôi chấp nhận rằng đó là yêu cầu hợp lệ, trong trường hợp nào là chuỗi số liệu không có khoảng trống * về số có vấn đề? Nhóm suy nghĩ thường xuyên sẽ có bạn tin rằng nó luôn luôn là, nhưng trên thực tế nó chỉ là một vấn đề tiềm năng trong những trường hợp rất cụ thể.

  1. Các dãy số phải không có khoảng trống.
  2. Nhiều quy trình tạo các thực thể mà số được liên kết (ví dụ: hóa đơn).
  3. Các số phải được tạo tại thời điểm thực thể được tạo.

Nếu tất cả các yêu cầu này phải được đáp ứng sau đó bạn có một điểm của serialization trong ứng dụng của bạn, và chúng tôi sẽ thảo luận rằng trong một khoảnh khắc.

Trước tiên, hãy nói về các phương pháp triển khai yêu cầu loạt số nếu bạn có thể xóa bất kỳ yêu cầu nào trong số đó.

Nếu chuỗi số của bạn có thể có khoảng trống (và bạn có nhiều quy trình yêu cầu tạo số ngay lập tức) thì hãy sử dụng đối tượng Oracle Sequence. Chúng có hiệu suất rất cao và các tình huống trong đó khoảng trống có thể được mong đợi đã được thảo luận rất tốt. Nó không phải là quá khó khăn để giảm thiểu số lượng bỏ qua bằng cách làm cho các nỗ lực thiết kế để giảm thiểu cơ hội của một thất bại quá trình giữa thế hệ của số và cam kết giao dịch, nếu đó là quan trọng.

Nếu bạn không có nhiều quy trình tạo các thực thể (và bạn cần một chuỗi số không có khoảng trống phải được tạo ngay), như trường hợp tạo hóa đơn hàng loạt, thì bạn đã có điểm của serialization. Điều đó có thể không phải là một vấn đề, và có thể là một cách hiệu quả để thực hiện thao tác cần thiết. Việc tạo ra các số khoảng trống là khá nhỏ trong trường hợp này. Bạn có thể đọc giá trị tối đa hiện tại và áp dụng giá trị gia tăng cho mỗi thực thể với một số kỹ thuật. Ví dụ, nếu bạn đang chèn một lô mới hoá đơn vào bảng hóa đơn của bạn từ một bàn làm việc tạm thời bạn có thể:

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

Tất nhiên bạn sẽ bảo vệ quá trình của bạn để chỉ một trường hợp có thể chạy cùng một lúc (có thể với DBMS_Lock nếu bạn đang sử dụng Oracle) và bảo vệ hóa đơn # bằng khóa duy nhất, và có thể kiểm tra các giá trị bị thiếu bằng mã riêng nếu bạn thực sự quan tâm.

Nếu bạn không cần tạo các số ngay lập tức (nhưng bạn cần chúng không có khoảng trống và nhiều quy trình tạo ra các thực thể) thì bạn có thể cho phép các thực thể được tạo và giao dịch được cam kết, và sau đó để lại số cho một công việc hàng loạt đơn lẻ. Bản cập nhật trên bảng thực thể hoặc chèn vào bảng riêng biệt.

Vì vậy, nếu chúng ta cần trifecta của thế hệ tức thời của một chuỗi các số không có khoảng trống bởi nhiều quy trình? Tất cả những gì chúng ta có thể làm là cố gắng giảm thiểu thời gian serialization trong quá trình, và tôi đưa ra lời khuyên sau đây, và chào đón bất kỳ lời khuyên bổ sung nào (hoặc tư vấn phản đối).

  1. cửa hàng giá trị hiện tại của bạn trong một bảng chuyên dụng. KHÔNG sử dụng một chuỗi.
  2. Đảm bảo rằng tất cả các quy trình đều sử dụng cùng một mã để tạo số mới bằng cách đóng gói nó trong một hàm hoặc thủ tục.
  3. Truy cập hàng loạt vào trình tạo số với DBMS_Lock, đảm bảo rằng mỗi chuỗi có khóa chuyên dụng riêng.
  4. Giữ khóa trong bộ tạo chuỗi cho đến khi giao dịch tạo thực thể của bạn hoàn tất bằng cách nhả khóa trên cam kết
  5. Làm chậm quá trình tạo số cho đến giây phút cuối cùng có thể.
  6. Hãy xem xét tác động của một lỗi không mong muốn sau khi tạo số và trước khi cam kết hoàn thành - ứng dụng sẽ cuộn lại một cách duyên dáng và nhả khóa hay nó sẽ giữ khóa trên trình tạo chuỗi cho đến khi phiên ngắt kết nối sau? Bất kể phương thức nào được sử dụng, nếu giao dịch thất bại thì số sê-ri phải được "trả về hồ bơi".
  7. Bạn có thể gói gọn toàn bộ thứ trong một trình kích hoạt trên bàn của thực thể không? Bạn có thể gói gọn nó trong một bảng hoặc cuộc gọi API khác chèn hàng và cam kết chèn tự động không?

Original article

+0

tôi cũng không thấy làm thế nào điều này sẽ giúp tôi, nơi tôi có postgresql và tôi thấy dữ liệu mà giao dịch bắt đầu. – GorillaApe

+0

Oralce và PostgreSQL có cùng một mô hình nhất quán đã đọc, do đó nguyên tắc khóa truy cập vào trình tạo số được áp dụng. –

+0

ok thì tôi cần loại khóa nào? Và làm thế nào điều này có thể làm việc trên mức cô lập tuần tự hóa? – GorillaApe