我有一個關於SQLAlchemy,數據庫分片和UUIDs的問題,對你來說很好的人。我目前使用的MySQLSQLAlchemy,UUIDs,Sharding和AUTO_INCREMENT主鍵......如何讓他們一起工作?
中,我有以下形式的表:
CREATE TABLE foo (
added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
id BINARY(16) NOT NULL,
... other stuff ...
UNIQUE KEY(id)
);
此表上的一些背景。我從不關心'added_id',我只是用來確保插入的項目在磁盤上聚集在一起(因爲用於索引MySQL表格的B-Tree使用主鍵作爲羣集索引)。 'id'列包含UUID的二進制表示 - 這是我真正關心的列,其他所有內容都引用此ID。同樣,我不希望UUID成爲主鍵,因爲UUID是隨機的,因此創建用於索引表的B-Tree具有可怕的IO特性(至少在其他地方已經說過了)。另外,雖然UUID1包含時間戳以確保ID按「順序」順序生成,但將MAC地址包含在ID中使其成爲我寧願避免的事情。因此,我想使用UUID4s。
好的,現在轉到SQLAlchemy部分。在SQLAlchemy的人們可以通過做一些像定義使用他們的ORM爲上表的模型:
# The SQL Alchemy ORM base class
Base = declerative_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)
...
再次,這是基本相同以上SQL。
現在來回答這個問題。假設這個數據庫將被分割(水平分割)成2個(或更多)獨立的數據庫。現在,(假設沒有刪除),這些數據庫中的每一個都將具有表foo中的1,2,3等的added_id的記錄。由於SQLAlchemy使用會話來管理正在處理的對象,以便每個對象僅由其主鍵標識,所以似乎可能會有可能結束嘗試從兩個對象中訪問兩個Foo對象的情況具有相同added_id的碎片導致受管會話中出現一些衝突。
有沒有人遇到過這個問題?你做了什麼來解決它?或者,更可能的是,我是否從SQLAlchemy文檔中錯過了一些確保不會發生的東西。然而,通過查看SQLAlchemy下載提供的分片示例(examples/sharding/attribute_shard.py),他們似乎通過將數據庫分片中的一個指定爲ID生成器來解決此問題......創建了一個隱含的瓶頸插入者必須違背那個單一的數據庫才能得到一個ID。 (他們還提到使用UUID,但顯然這會導致索引性能問題。)
或者,有沒有辦法將UUID設置爲主鍵,並使用added_id將數據聚集在磁盤上?如果在MySQL中不可能的話,可以在Postgres之類的其他數據庫中使用?
在此先感謝您的任何和所有的投入!
--- UPDATE ---- 我只是想添加一個帶外答案,我收到了這個問題。下面的文本不是我寫的,我只是想在這裏包括它,以防有人發現它有用。
使用MySQL和自動遞增鍵避免這種情況的最簡單方法是爲每個數據庫使用不同的自動遞增偏移量,例如,:
ALTER TABLE foo AUTO_INCREMENT = 100000;
缺點是您需要注意如何配置每個分片,並且您需要計劃一下您使用的分片的總數。
沒有任何方法說服MySQL使用非主鍵作爲聚簇索引。如果您不關心使用SQLAlchemy來管理數據庫模式(儘管您可能應該這樣做),則可以簡單地將UUID設置爲SQLAlchemy模式中的主鍵,並將add_id作爲pk留在實際表中。
我還看到了一些簡單地使用外部服務器(例如redis)來維護行ID的替代解決方案。
非常感謝。 – prschmid