首先,我想说的是,我知道SQL身份功能为何以及如何工作,以缓存将要使用的身份值,并且预期不会出现空白。因此,例如,在服务器重新启动后,it can jump 1000/10000 values depending on the identity data type,并且我确实知道该身份应该毫无意义。
但是,很多年前,我在旧的SQL Server版本上开发了链接缩短器,该链接器的行为不像上面那样。此链接缩短器使用Id列生成url的缩短部分。
升级SQL Server版本后,差距开始出现。
包含要缩短的链接的表类似于以下内容(注意空格):
Id | Url
---------------------------------
1 | http://foo.bar
2 | http://bar.foo
10001 | http://google.com
20001 | http://stackoverflow.com
然后,我的应用程序将上述链接缩短为以下内容(这不是数据库表):
Id | ShortenedUrl
---------------------------------
1 | foo.bar/a
2 | foo.bar/b
10001 | foo.bar/fZ2sh
20001 | foo.bar/bbSz1
(仅说明一下,它并不像1 = a,2 = b那样简单)
所以现在我有一个问题:使用链接缩短器的全部目的是生成短链接。现在我有4个多余的字符。
我不能仅仅使用row_number() OVER (ORDER BY [ID])
函数,因为生产中的数据已经丢失/错误生成了。
在生成下一个缩短的链接时,使用间隙的方式有什么可能性?
更多信息:
我可以创建另一个列,该列从Id列(对于已经存在的列)中导入数据,并通过过程(称为数据插入)开始使用新逻辑,从而锁定需要锁定以获取下一个可用间隙的任何内容新行的编号。
该表当前仅在MVC应用程序上使用(没有指向它的外键)。当前正在通过直接插入来插入数据,但是我可以更新该应用程序以使用(新)过程。换句话说,表结构可以更改,其中的信息不能更改。
答案 0 :(得分:0)
一个选择是用sequence替换身份。您仍然需要修复错误的数据,但这可以使URL与密钥分开。
但是从我的角度来看,现有的起酥油需要一些工作。
使用好的算法,20001
值不需要超过3个字符。
如果您使用两个额外的“特殊”字符,则可以在缩短的url(AZ,az,0-9和我们的特殊字符。和_)中为每个字符获取64个可能的值,足以存储六位数据。我们已经以这种方式进行了base-64编码,但是由于您只有数字,因此可以提高效率。
采用20001
之类的数字,将其转换为二进制:
100111000100001
左数为零,因此二进制数字的数量是六的倍数:
000100111000100001
将其分成六组:
000100 111000 100001
这些组中的每个组都应映射到单个可能的字符。要获取原始ID#,请反过来做同样的事情。
使用此方案,您需要先进入262143
,然后再将第4个字符添加到URL中,再添加16777215
,然后再添加第5个字符,然后再添加1073741823
第六名。
为了娱乐,下面是一些C#代码进行转换:
private static char[] charMap = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '.', '_'};
public static string GetURLKey(int id)
{
if (id <= 0) return "0";
var bt = new byte[32];
int pos = 32;
while (id > 0)
{
pos--;
bt[pos] = (byte)(id % 2);
id >>= 1;
}
var bts = new Span<byte>(bt, pos, 32-pos);
var r = 6 - (bts.Length % 6);
if (r == 6) r = 0;
return string.Create((bts.Length + r) / 6, bts.ToArray(), (span, arr) =>
{
int curChar = 0, charPos = r, bitArrPos = 0, curVal = 0;
while (bitArrPos < arr.Length)
{
while (bitArrPos < arr.Length && charPos < 6)
{
curVal *= 2;
curVal += (int)arr[bitArrPos];
bitArrPos++;
charPos++;
}
span[curChar] = charMap[curVal];
curVal = 0;
charPos = 0;
curChar++;
}
});
}