Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database SQLAlchemy、UUID、分片和自动增量主键。。。如何让他们一起工作?_Database_Performance_Sqlalchemy_Uuid_Sharding - Fatal编程技术网

Database SQLAlchemy、UUID、分片和自动增量主键。。。如何让他们一起工作?

Database SQLAlchemy、UUID、分片和自动增量主键。。。如何让他们一起工作?,database,performance,sqlalchemy,uuid,sharding,Database,Performance,Sqlalchemy,Uuid,Sharding,我有一个关于SQLAlchemy、数据库切分和UUID的问题要问你们 我目前正在使用MySQL,其中我有一个如下表: CREATE TABLE foo ( added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BINARY(16) NOT NULL, ... other stuff ... UNIQUE KEY(id) ); 这张桌子上有一点背景。我从不关心“added_id”,我只使用它来确保插入的项在磁盘上

我有一个关于SQLAlchemy、数据库切分和UUID的问题要问你们

我目前正在使用MySQL,其中我有一个如下表:

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树使用主键作为聚集索引)。“id”列包含UUID的二进制表示形式——这是我真正关心的列,所有其他东西都引用这个id。同样,我不希望UUID成为主键,因为UUID是随机的,因此创建索引表的B树具有可怕的IO特征(至少其他地方已经说过了)。此外,尽管UUID1包含时间戳以确保ID按“顺序”生成,但在ID中包含MAC地址使其成为我宁愿避免的事情。因此,我希望使用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中具有添加的_id为1、2、3等的记录。由于SQLAlchemy使用会话来管理正在处理的对象,因此每个对象仅由其主键标识,因此似乎有可能出现这样的情况:我可以结束尝试从两个表中访问两个foo对象的过程具有相同添加的_id的硬盘导致托管会话中出现一些冲突

有人遇到过这个问题吗?你做了什么来解决它?或者,更有可能的是,我在SQLAlchemy文档中遗漏了一些确保这种情况不会发生的东西。但是,看看SQLAlchemy下载提供的切分示例(examples/sharding/attribute_shard.py)他们似乎回避了这个问题,将其中一个数据库碎片指定为ID生成器……这造成了一个隐式瓶颈,因为所有插入都必须与单个数据库相冲突才能获得ID(他们还提到使用UUID,但显然这会导致索引的性能问题)

或者,是否有办法将UUID设置为主键,并使用添加的_id将数据聚集在磁盘上?如果在MySQL中不可能,那么在其他数据库(如Postgres)中是否可能

提前感谢您的任何和所有输入

---更新---- 我只想添加一个我收到的关于这个问题的带外答案。下面的文本不是我写的,我只想在这里包括它,以防有人发现它有用

使用MySQL和自动增量键避免这种情况的最简单方法是为每个数据库使用不同的自动增量偏移量,例如:

更改表foo AUTO_INCREMENT=100000

缺点是,您需要注意如何配置每个碎片,并且需要计划使用的碎片总数

没有任何方法可以说服MySQL为聚集索引使用非主键。如果您不关心使用SQLAlchemy来管理数据库架构(尽管您可能应该这样做),您可以简单地将UUID设置为SQLAlchemy架构中的主键,并将add_id保留为实际表中的pk

我还看到了一些替代解决方案,它们只是使用外部服务器(例如redis)来维护行id


是的,您可以使用“primary_key”映射器参数(列对象列表或单列)将表中的任何列指定为映射的主键:

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核心将“add_id”视为“autoincrement”列,但映射程序对它基本上不感兴趣,而是在考虑对象的“标识”时使用“id”作为它关心的列

有关详细说明,请参阅