2012-10-31 54 views
5

我有一个关于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的替代解决方案。

回答

5

是的,你可以指定任何表列的为使用“primary_key”映射的说法,这是Column对象的列表或单个列映射的目的,主键:

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} 

上面,尽管SQLAlchemy Core会将“add_id”视为“autoincrement”列,但映射器大多不会对其感兴趣,而是在考虑对象的“身份”时使用“id”作为关注的列。

查看documentation for mapper()了解更多描述。

+0

非常感谢。 – prschmid

相关问题