2012-04-18 23 views
5

Tôi có một dự án nuôi thú cưng SaaS để lập hóa đơn. Trong đó, tôi muốn khách hàng của tôi bắt đầu với số vé 1001. Rõ ràng, tôi không thể sử dụng trường tự động đơn giản trong Postgres và chỉ thêm 1000 vào giá trị, bởi vì tất cả khách hàng của tôi sẽ chia sẻ cùng một cơ sở dữ liệu và cùng một bảng tickets .. Tôi đã thử sử dụng một kiểu cột nguyên và truy vấn (giả SQL) SELECT LATEST number FROM tickets WHERE client_id = [current client ID] để lấy số mới nhất, và sau đó sử dụng số đó + 1 để nhận số number tiếp theo. Vấn đề là với sự đồng thời, nó có thể dễ dàng cho hai vé để kết thúc với cùng một con số theo cách này. số lượng tôi cần để có thể làm điều này trong Django hoặc với SQL thô (vs sử dụng Bash hoặc bất cứ điều gì khác của loại).Cách thích hợp để tự sắp xếp một cột trong Postgres là gì?

Tôi không tìm cách ép buộc ví dụ của mình hoạt động. Tôi chỉ đang tìm một giải pháp cho vấn đề của tôi là cần tăng số lượng vé độc lập cho mỗi khách hàng.

+1

Có thể dupe: http://stackoverflow.com/questions/6046085/postgresql-sequence-that-ensure-a-unique-id –

+0

Không trùng lặp vì tìm kiếm một số duy nhất. Tôi đang tìm số tiếp theo theo thứ tự liên quan đến một trường khác (trường khách hàng). Trong thực tế, tôi nói rằng tôi không thể sử dụng một trường tự động (tức là, nối tiếp). – orokusaki

+0

OK, giờ tôi đã hiểu. Hy vọng câu trả lời của tôi phù hợp với bạn (hoặc, tốt hơn, một người nào đó có thứ gì đó thanh lịch hơn). –

Trả lời

5

Tôi không nghĩ rằng có giải pháp "rẻ" cho vấn đề này. Giải pháp duy nhất an toàn (nhưng không nhất thiết phải nhanh) trong môi trường đa người dùng là có bảng "phản đối" với một hàng cho mỗi khách hàng.

Mỗi giao dịch phải đầu tiên khóa nhập của khách hàng trước khi chèn một vé mới, một cái gì đó như thế này:

UPDATE cust_numbers 
    SET current_number = current_number + 1 
WHERE cust_id = 42 
RETURNING current_number; 

Điều đó sẽ làm ba việc trong một bước

  1. tăng "tuần tự" hiện tại số cho khách hàng đó
  2. khóa hàng để các giao dịch khác thực hiện tương tự sẽ phải đợi khóa
  3. trả về giá trị mới của thứ tại cột.

Với số mới đó, bây giờ bạn có thể chèn một vé mới. Nếu giao dịch được cam kết, nó cũng sẽ giải phóng khóa trên bảng cust_numbers, do đó các giao dịch khác "đang chờ một số" có thể tiếp tục.

Bạn có thể bao gồm hai bước (cập nhật .. trả về & việc chèn) vào một hàm được lưu trữ duy nhất để logic đằng sau này được tập trung. Đơn đăng ký của bạn sẽ chỉ gọi số select insert_ticket(...) mà không biết số vé được tạo ra như thế nào.

Bạn cũng có thể muốn tạo trình kích hoạt trên bảng khách hàng để tự động chèn hàng vào bảng cust_numbers khi khách hàng mới được tạo.

Điểm bất lợi của việc này là bạn sắp xếp một cách hiệu quả các giao dịch đang chèn vé mới cho cùng một khách hàng. Tùy thuộc vào volumn của chèn trong hệ thống của bạn điều này có thể bật ra được một vấn đề hiệu suất.

Sửa
Một nhược điểm của việc này là, rằng bạn không phải buộc để chèn vé như vậy mà có thể dẫn đến vấn đề nếu ví dụ một nhà phát triển mới quên điều này.

+0

Tuyệt vời, cảm ơn! Câu hỏi mặc dù, A) khóa này sẽ được cho toàn bộ bảng, hoặc tôi có thể khóa một hàng duy nhất? Tôi sẽ không muốn tất cả 2000 khách hàng phải chờ khóa này từ máy khách X được phát hành trước khi họ có thể tạo thêm vé (tưởng tượng 2-3 vé mỗi giây), và B) Điều gì xảy ra (và phục hồi thích hợp là gì đường dẫn), nếu một truy vấn kết nối thứ hai cho số này trong khi nó bị khóa? re: "serialize các giao dịch" - làm thế nào nó sẽ là một vấn đề hiệu suất khi các giao dịch vé trước đó phải hoàn thành trước những giao dịch mới. Nó là một vấn đề lớn? Tôi sẽ có âm lượng cao. – orokusaki

+2

@orokusaki: Như tôi đã mô tả: chỉ có hàng cho khách hàng đó sẽ bị khóa. Kết nối thứ hai sẽ đợi cho đến khi các cam kết đầu tiên. Có, điều này sẽ làm giảm hiệu suất của bạn. Nhưng bạn có thể có được những con số như thế này (chậm nhưng an toàn) hoặc nhận được chúng nhanh chóng bằng cách sử dụng một chuỗi nhưng sau đó họ sẽ là duy nhất trên tất cả các khách hàng. Bạn phải quyết định điều gì quan trọng hơn –

2

Bạn có thể tạo chuỗi cho từng khách hàng và sau đó đặt giá trị của cột thành nextval('name_of_the_sequence'). Đây thực sự là cách hoạt động của serial; sự khác biệt duy nhất trong trường hợp của bạn là bạn không sử dụng giá trị mặc định cho cột và có nhiều hơn một chuỗi.

Tạo các trình tự đó chọn đúng trình tự khi chèn một hàng mới có thể được thực hiện tốt thông qua quy trình PL/Pgsql.

+0

Ngoài vấn đề cần 2000 cột để thực hiện việc này, vấn đề cơ bản khi sử dụng trường nối tiếp là giao dịch cuộn lùi vẫn sử dụng số mà 'nextval' trả về, vì vậy nếu số vé cho một khách hàng nhất định có thể là 1001, 1002, 1005, 1007, v.v., so với việc duy trì một chuỗi thực (ví dụ, giá trị của một cột nối tiếp không phải là một thước đo chính xác về số lượng thẻ). – orokusaki

+0

Vui lòng đọc câu trả lời của tôi. Tôi không nói về các cột nối tiếp hoặc các cột khác nhau. Bạn có thể tạo các chuỗi riêng biệt và tìm nạp các giá trị từ chúng bằng cách sử dụng 'nextval()' – ThiefMaster

+0

@ThiefMaster, bạn có gợi ý tạo chuỗi trong trình kích hoạt (chèn khách hàng) và sau đó yêu cầu SQL động để chọn các giá trị không? (Tôi là một Postgres noob, vì vậy tôi không chắc chắn nếu bất kỳ điều này thậm chí có thể, nhưng có lẽ OP cần một cách tự động để làm công cụ này) –

Các vấn đề liên quan