如何在SQL中实现多个表的全局递增id?

发布于 2024-12-09 14:30:36 字数 441 浏览 0 评论 0原文

当我编码时,我决定为每种类型的内容使用不同的表格。现在我被困在解决这个问题上。基本上,我的通知系统当前按时间戳对最新内容进行排名。然而,这是不准确的,因为某人与另一个人同时提交内容的可能性很小,并且会出现不正确的排名。

现在,如果我将所有内容放在一个表中,我只需通过自动递增变量对其进行排名即可。有没有办法在多个表中实现这种自动递增整数(例如,当将某些内容插入table1,id=0时,将某些内容插入table2,id=1 )。或者我是否必须将所有内容重新编码到一个表中。

注意:

我在多个表中包含内容的原因是因为它是有组织的并且可以减少负载压力。我不再关心组织了,因为我可以通过我编码的 GUI 访问数据,我只是想知道负载压力。

编辑:

我正在使用 PHP 5 和 MySQL。

I decided back when I was coding to have different tables for each type of content. Now I am stuck solving this. Basically my notification system ranks the newest content by its timestamp currently. This is inaccurate however because there is a small chance that someone would submit content at the same time as another person, and incorrect ranking would occur.

Now if I had all my content in a single table, I would simply rank it by an auto-incrementing variable. Is there a way to implement this auto-increment integer across multiple tables (e.g. When something is inserted into table1, id=0, something is inserted into table2, id=1). Or do I have to recode all my stuff into a single table.

NOTE:

The reason I have content in multiple tables is because its organized and it would reduce load stress. I don't really care about the organization anymore, because I can just access the data through a GUI I coded, I'm just wondering about the load stress.

EDIT:

I'm using PHP 5 with MySQL.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

下雨或天晴 2024-12-16 14:30:36

您的问题,特别是跨多个表的 ID 的需求,清楚地表明您的数据库设计需要更改。您应该为所有内容类型创建一张表(作为概括),并具有自动递增 ID。然后,对于每个特定的内容类型,您可以定义具有额外字段的其他表(相当于 OOP 中的继承)以及指向基本表的外键。

换句话说,您需要类似于SQL 中的继承

Your question, particularly the need for ID spanning over multiple tables, is clearly signalizing that your database design needs change. You should make one table for all content types (as a generalization), with autoincrementing ID. Then, for each particular content type, you can define other table (equivalent of inheritance in OOP) with extra fields, and foreign key pointing to the basic table.

In other words, you need something like inheritance in SQL.

太阳哥哥 2024-12-16 14:30:36

您可以创建一个具有自动增量 ID 的表来跟踪 ID。您的程序将在该表上执行插入操作,获取 id,并根据需要使用它。

大致如下:

function getNextId() {
    $res = mysql_query("INSERT INTO seq_table(id) VALUES (NULL)");
    $id = mysql_insert_id();
    if ($id % 10 == 0) {
        mysql_query("DELETE FROM seq_table");
    }
    return $id;
}

其中 seq_table 是您必须创建的表,只是为了获取 id。使其成为一个函数,以便在需要时可以使用它。每生成 10 个 id,我就会删除所有生成的 id,无论如何,您在那里不需要它们。我不会每次都删除,因为它会减慢速度。如果同时发生另一次插入并且我删除了 11 条或更多记录,则不会影响此过程的行为。对于它必须达到的目的而言,它是安全的。

即使表为空,新的 id 也会继续增长,因为您已将 id 声明为自动增量。

更新:我想澄清为什么 ID 生成没有包含在事务中以及为什么不应该包含在事务中。

如果您生成自动 ID 并回滚事务,则下一个自动 ID 无论如何都会递增。摘自 MySQL 错误报告

[...] 这不是一个错误,而是我们知道的每个 RDBMS 中都会发生的预期行为。生成的值不是事务的一部分,也不关心其他语句。

使用此过程获取 ID 是完全线程安全的。获取 ID 后的逻辑应该包装在事务中,尤其是在处理多个表时。

以这种方式获取序列并不是一个新概念,例如 metabase_mysql.php 是一个稳定的数据库访问库,有一个名为 GetSequenceNextValue() 的方法,它非常相似。

You can create a table with auto increment id just to keep track of ids. Your program would do an insert on that table, get the id, use it as necessary.

Something along the lines of:

function getNextId() {
    $res = mysql_query("INSERT INTO seq_table(id) VALUES (NULL)");
    $id = mysql_insert_id();
    if ($id % 10 == 0) {
        mysql_query("DELETE FROM seq_table");
    }
    return $id;
}

Where seq_table is a table that you've to create just to get the ids. Make it a function so it can be used whenever you need. Every 10 ids generated I delete all generated ids, anyway you don't need them there. I don't delete every time since it would slow down. If another insert happen in the meantime and I delete 11 or more records, it doesn't affect the behaviour of this procedure. It's safe for the purpose it has to reach.

Even if the table is empty new ids will just keep on growing since you've declared id as auto-increment.

UPDATE: I want to clarify why the ID generation is not wrapped in a transaction and why it shouldn't.

If you generate an auto id and you rollback the transaction, the next auto id, will be incremented anyway. Excerpt from a MySQL bug report:

[...] this is not a bug but expected behavior that happens in every RDBMS we know. Generated values are not a part of transaction and they don't care about other statements.

Getting the ID with this procedure is perfectly thread safe. Your logic after the ID is obtained should be wrapped in a transaction, especially if you deal with multiple tables.

Getting a sequence in this way isn't a new concept, for instance, the code of metabase_mysql.php which is a stable DB access library has a method called GetSequenceNextValue() which is quite similar.

缺⑴份安定 2024-12-16 14:30:36

在单个表中,您可以有一个内容类型字段和包含内容类型字段的聚集索引。这有效地将所有一种内容类型保留在光盘上的一个位置,并将另一种内容类型保留在另一个位置,等等。(它实际上组织成页面,但这种物理组织仍然如此。)

假设每种内容类型具有相同的字段,这可能会满足您的需求,并且行为与多个表类似。在某些情况下,您甚至可能会发现,通过适当的索引,单表解决方案可以更快、更方便且可维护等。例如尝试跨所有内容类型创建全局唯一标识符。

如果您无法将它们合并回单个表,您可以创建一个中央链接表...

CREATE TABLE content_link (
  id            INT IDENTITY(1,1),         -- MS SQL SERVER syntax
  content_type  INT,
  content_id    INT                        -- The id from the real table
)

在插入内容表时,也插入链接表以创建您的全球唯一 ID。

更简单,但更手动,只需在数据库中的某个位置保存一个值即可。每当您需要新的 ID 时,请使用该集中存储的值并将其加一。请务必将增量和集合包装在单个事务中以停止竞争条件。 (这可以通过多种方式完成,具体取决于您的 SQL 风格。)

编辑

来自网络的几行 MySQL 示例代码...

START TRANSACTION;
INSERT INTO foo (auto,text)
    VALUES(NULL,'text');         # generate ID by inserting NULL
INSERT INTO foo2 (id,text)
    VALUES(LAST_INSERT_ID(),'text');  # use ID in second table
COMMIT TRANSACTION;

就个人而言,我实际上会将值存储在变量中,提交事务,然后继续我的业务逻辑。这将使表上的锁保持在最低限度。

In a single table, you could have a field for the content type and clustered index that includes the content type field. This effectively keeps all of one content type in one place on the disc, and another content type in another place, etc. (It's actually organised into pages, but this physical organisation is still true.)

Assuming that each content type has the same fields, this would likely meet your needs and behave similarly to multiple tables. In some cases you may even find that, with appropriate indexes, a single table solution can be faster, more convenient and maintainable, etc. Such as trying to create global unique identifiers across all content types.

If you're unable to merge these back into a single table, you could create a central link table...

CREATE TABLE content_link (
  id            INT IDENTITY(1,1),         -- MS SQL SERVER syntax
  content_type  INT,
  content_id    INT                        -- The id from the real table
)

As you insert into the content tables, also insert into the link table to create your globally unique id.

More simply, but even more manually, just hold a single value somewhere in the database. Whenever you need a new id, use that centrally stored value and increment it by one. Be sure to wrap the increment and collection in a single transaction to stop race conditions. (This can be done in a number of ways, depending on your flavor of SQL.)

EDIT

A couple of MySQL example lines of code from the web...

START TRANSACTION;
INSERT INTO foo (auto,text)
    VALUES(NULL,'text');         # generate ID by inserting NULL
INSERT INTO foo2 (id,text)
    VALUES(LAST_INSERT_ID(),'text');  # use ID in second table
COMMIT TRANSACTION;

Personally, I'd actually store the value in a variable, commit the transaction, and then continue with my business logic. This would keep the locks on the tables to a minimum.

清旖 2024-12-16 14:30:36

您可以有一个单独的 ID 表,将其插入其中,然后使用新插入的 ID。

例如

CREATE TABLE ids (INT UNSIGNED AUTO INCREMENT PRIMARY KEY, timeadded DATETIME);

在脚本中:

<?php
$r = mysql_query('INSERT INTO ids (timeadded) VALUES (NOW())');
$id = mysql_insert_id();
mysql_query("INSERT INTO someOtherTable (id, data) VALUES ('$id', '$data)");

添加错误检查等以适应口味。

MySQL 手册指出:

生成的 ID 保存在服务器上
每个连接的基础。这意味着返回的值
给定客户端的函数是生成的第一个 AUTO_INCRMENT 值
对于影响 AUTO_INCREMENT 列的最新语句
客户。该值不会受到其他客户端的影响,即使他们
生成自己的 AUTO_INCRMENT 值。这种行为确保
每个客户端都可以检索自己的 ID,而无需关心
其他客户端的活动,并且不需要锁或
交易。

来源)所以我不要认为对 ACID 合规性的担忧是一个问题。

You could have a separate ID table, insert into that, and use the newly-inserted ID.

e.g.

CREATE TABLE ids (INT UNSIGNED AUTO INCREMENT PRIMARY KEY, timeadded DATETIME);

In the script:

<?php
$r = mysql_query('INSERT INTO ids (timeadded) VALUES (NOW())');
$id = mysql_insert_id();
mysql_query("INSERT INTO someOtherTable (id, data) VALUES ('$id', '$data)");

Add error checking etc. to taste.

The MySQL manual states:

The ID that was generated is maintained in the server on a
per-connection basis. This means that the value returned by the
function to a given client is the first AUTO_INCREMENT value generated
for most recent statement affecting an AUTO_INCREMENT column by that
client. This value cannot be affected by other clients, even if they
generate AUTO_INCREMENT values of their own. This behavior ensures
that each client can retrieve its own ID without concern for the
activity of other clients, and without the need for locks or
transactions.

(Source) So I don't think concerns about ACID complians are a problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文