2012-10-31 38 views
5

Tôi có một câu hỏi liên quan đến SQLAlchemy, sharding cơ sở dữ liệu và UUID cho bạn những người tốt.SQLAlchemy, UUID, Sharding và AUTO_INCREMENT khóa chính ... làm cách nào để chúng hoạt động cùng nhau?

Tôi hiện đang sử dụng MySQL trong đó tôi có một bảng có dạng:

CREATE TABLE foo (
    added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    id BINARY(16) NOT NULL, 
    ... other stuff ... 
    UNIQUE KEY(id) 
); 

Một nền chút trên bảng này. Tôi không bao giờ quan tâm đến 'add_id', tôi chỉ sử dụng để đảm bảo rằng các mục được chèn được nhóm lại với nhau trên đĩa (vì B-Tree được sử dụng để lập chỉ mục bảng trong MySQL sử dụng khóa chính làm chỉ mục cụm). Cột 'id' chứa biểu diễn nhị phân của UUID - đây là cột mà tôi thực sự quan tâm và tất cả những thứ khác đều tham chiếu đến ID này. Một lần nữa, tôi không muốn UUID là khóa chính, vì UUID là ngẫu nhiên và do đó làm cho B-Tree được tạo ra để lập chỉ mục bảng có các đặc tính IO khủng khiếp (ít nhất đó là những gì đã được nói ở nơi khác). Ngoài ra, mặc dù UUID1 bao gồm dấu thời gian để đảm bảo rằng ID được tạo theo thứ tự "tuần tự", việc đưa địa chỉ MAC vào ID làm cho nó trở thành thứ tôi muốn tránh. Vì vậy, tôi muốn sử dụng UUID4s.

Ok, bây giờ hãy chuyển sang phần SQLAlchemy. Trong SQLAlchemy người ta có thể định nghĩa một mô hình bằng cách sử dụng ORM của họ cho bảng trên bằng cách làm một cái gì đó như:

Một lần nữa, điều này về cơ bản giống như SQL ở trên.

Và bây giờ cho câu hỏi. Giả sử rằng cơ sở dữ liệu này sẽ được phân đoạn (phân vùng theo chiều ngang) thành 2 (hoặc nhiều) cơ sở dữ liệu riêng biệt. Bây giờ, (giả sử không xóa), mỗi cơ sở dữ liệu này sẽ có các bản ghi với plus_id của 1, 2, 3, vv trong bảng foo. Vì SQLAlchemy sử dụng một phiên để quản lý các đối tượng đang được làm việc để mỗi đối tượng được xác định chỉ bằng khóa chính của nó, có vẻ như có thể có tình huống mà tôi có thể kết thúc cố gắng truy cập hai đối tượng Foo từ hai phân đoạn với cùng một dữ liệu đã dẫn đến một số xung đột trong phiên được quản lý.

Có ai gặp sự cố này không? Bạn đã làm gì để giải quyết nó? Hoặc, nhiều khả năng, tôi thiếu một cái gì đó từ tài liệu SQLAlchemy để đảm bảo rằng điều này không thể xảy ra. Tuy nhiên, nhìn vào ví dụ sharding được cung cấp với tải xuống SQLAlchemy (ví dụ/sharding/attribute_shard.py), chúng dường như đã giải quyết vấn đề này bằng cách chỉ định một trong các bộ phận cơ sở dữ liệu như một trình tạo ID ... INSERTS phải đi ngược lại cơ sở dữ liệu duy nhất đó để lấy một ID. (Họ cũng đề cập đến việc sử dụng UUID, nhưng rõ ràng là gây ra vấn đề hiệu suất cho các chỉ mục.)

Ngoài ra, có cách nào để đặt UUID làm khóa chính và dữ liệu được nhóm trên đĩa bằng cách sử dụng add_id không? Nếu nó không thể trong MySQL là nó có thể trong một DB như Postgres?

Cảm ơn trước cho bất kỳ và tất cả đầu vào!

--- CẬP NHẬT ---- Tôi chỉ muốn thêm câu trả lời ngoài băng mà tôi đã nhận được cho câu hỏi này. Các văn bản sau đây không phải là một cái gì đó tôi đã viết, tôi chỉ muốn bao gồm nó ở đây trong trường hợp ai đó thấy nó hữu ích.

Cách dễ nhất để tránh tình huống đó bằng các phím tăng dần của MySQL và tự động là sử dụng các chênh lệch tăng tự động khác nhau cho từng cơ sở dữ liệu, ví dụ::

ALTER TABLE foo AUTO_INCREMENT = 100000;

Nhược điểm là bạn cần phải quan tâm đến cách bạn định cấu hình từng phân đoạn, và bạn cần lập kế hoạch một chút wrt tổng số phân đoạn bạn sử dụng.

Không có cách nào để thuyết phục MySQL sử dụng khóa không phải chính cho chỉ mục nhóm. Nếu bạn không quan tâm đến việc sử dụng SQLAlchemy để quản lý lược đồ cơ sở dữ liệu của mình (mặc dù, có thể bạn nên), bạn có thể chỉ cần đặt UUID làm khóa chính trong lược đồ SQLAlchemy và để lại add_id làm pk trong bảng thực tế.

Tôi cũng đã thấy các giải pháp thay thế chỉ đơn giản sử dụng máy chủ bên ngoài (ví dụ: redis) để duy trì id hàng.

Trả lời

5

có, bạn có thể chỉ định bất kỳ các cột của bảng làm khóa chính cho các mục đích của việc lập bản đồ bằng cách sử dụng lập luận mapper "primary_key", mà là một danh sách các đối tượng Cột hoặc một cột duy nhất:

Base = declarative_base() 

# The model for table 'foo' 
class Foo(Base): 
    __table__ = 'foo' 
    add_id = Column(Integer, primary_key=True, nullable=False) 
    id = Column(Binary, index=True, unique=True, nullable=False) 

    __mapper_args__ = {'primary_key': id} 

Ở trên, trong khi lõi SQLAlchemy sẽ coi "add_id" là cột "tự động", người lập bản đồ sẽ hầu như không quan tâm đến nó, thay vì sử dụng "id" làm cột mà nó quan tâm khi xem xét "nhận dạng" của đối tượng .

Xem documentation for mapper() để biết thêm mô tả.

+0

Cảm ơn một triệu. – prschmid

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