如何在php中创建自己的自动增量?

vbkedwbf  于 2022-10-22  发布在  PHP
关注(0)|答案(4)|浏览(170)

MySQL中内置的自动增量不符合我的要求,所以我正在考虑制作一个新的。这是我的要求:
1.创建增量序列号
1.能够将行(记录)插入缺失的编号。例如,我有5行,然后删除第3行。之后,我又插入了2行。我希望其中一个将插入到第三行位置。
我的想法是使用循环检查表中的所有行。如果它找到了丢失的位置,它将在丢失的位置添加(a)新行。否则,它将继续在表的末尾添加新行。
正如你所见,这个想法只适用于非常小的table。如果表扩展到,比如10MB。然后服务器会遇到很大的麻烦。
我想知道是否有人有更好的算法,请告诉我。

zkure5ic

zkure5ic1#

在自动增量列中填充空白通常是不必要的,而且比实际情况更麻烦。自动增量不是行号。它不需要是连续的,它只需要是唯一的。
如果你想填补空白,你会发现的一个问题是race condition。也就是说,在你的PHP脚本找到要使用的空白并插入该空白之间的毫秒内,另一个PHP请求可能正在做同样的事情,找到相同的空白,然后去填补它。
为了解决这个问题,PHP脚本必须在搜索要使用的间隙之前锁定整个表。由于您正在搜索间隙,其中没有具有给定值的行,因此无法锁定任何行。您必须锁定整个表,因为您在搜索差距之前不知道差距在哪里(如果存在差距)。
使用表锁定是一种代价高昂的牺牲,因为这意味着一次只能插入一个PHP请求。这将成为应用程序可伸缩性的瓶颈。
现在谈谈您的实现。如何找到丢失的号码?这些数字在数据库中,因此您可以查询查找表中没有前面的id的任何id。

SELECT t1.id FROM mytable AS t1 
LEFT OUTER JOIN mytable AS t1 ON t2.id = t1.id - 1
WHERE t2.id IS NULL
ORDER BY t1.id
LIMIT 1

另一种方法是在应用程序中保留所有id的某种缓存。但这也意味着每个并发的PHP请求都需要访问缓存,以及锁定缓存的能力,这样一次只能有一个PHP请求搜索和更新缓存。
不管怎样,您都为您的应用程序创建了一个瓶颈。
我在我的书《SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming》的一章中写了更多关于这一点的内容。

isr3a4wc

isr3a4wc2#

在实践中,您必须非常小心并真正知道自己在做什么,因为以这种方式填充id列中的“空白”可能会破坏整个数据库或系统的引用完整性,因为该表中的id被其他表引用。
否则,一种快速的方法是先使用mysql通过现有行填充这些“空”id,例如使用phpmyadmin,在确保表在id列上按升序排序后,使用如下内容:

SET @count = 0;
 UPDATE the_table SET id = @count:= @count + 1;
 #Then after this you do your insert operations.

上面的操作将按顺序更新所有现有的id,并且您插入的项将被自动增加为等于表中总行数的id。
但是如果你想保留已经非空的id,那么你可以在PHP中这样做:

/* Assume that you want to insert into a table called the_table with columns id, col1, col2, col3 a new row with values for the three cols 
$value1, $value2, $value3 respectively, using an existing 'gap' in the id numbering: */

/* Get an array of all present ids: */
$arr = []; 
$q1 = mysqli_query($con,"SELECT id from the_table");
while(list($id) = mysqli_fetch_array($q1)){
$arr[] = $id;
} 

/* Get the currently largest id in the table as $largest_id */
$q2 = mysqli_query($con,"SELECT MAX(id) from the_table");
list($largest_id) = mysqli_fetch_array($q2);

/* Loop through all integers up to $largest_id + 1 */
/* And do the insert operation just one time, once you find a number not in $arr */
/* Use the $not_yet_inserted variable to break out of the loop */
$not_yet_inserted = true;
for($j = 1; $j <= $largest_id + 1; $j += 1){
    if(!in_array($j,$arr) && $not_yet_inserted ){ 
    mysqli_query($con,"INSERT INTO the_table (id, col1, col2,col3) values ('$j','$value1','$value3,'$value3'')");
    $not_yet_inserted = false;
    }
}
rxztt3cl

rxztt3cl3#

你可以使用二进制搜索算法。
首先将所有ID插入数据库。然后将最大id与列表长度进行比较。如果两者相同,则插入具有下一个id的行。如果不是,则比较列表一半的id和length/2。现在,如果两者相同,则表示缺少的id位于列表的前半部分之后,否则它位于列表的上半部分。希望你能理解我想说的话。

bf1o4zei

bf1o4zei4#

不要删除行。在插入时包含一个布尔字段“reuseflag”=false。
要“删除”行,请将重用标志设置为true,并将行选择更改为仅包含一行(如果重用标志为false)
然后,当您想重用一行时,首先找到reuseflag=true的位置,插入新值并在更新行之前将reusefla更改为false。
这将比你能做的任何其他方法都快。

相关问题