识别记录的随机字符串?

时间:2018-06-28 17:33:00

标签: sql database

我想做些类似imgur和其他大多数网站的事情:我想在URL中使用随机字符串来标识用户正在寻找的帖子。

使用像这样的随机字符串作为主键可能不是一个好主意,并且在用户发送提交时确保随机生成的字符串尚未被使用会随着时间的流逝而减慢表的速度。 ,因为它将需要检查越来越多的记录以确保没有重复项。如何实现像这样的随机字符串以进行识别?

我的想法是,请告诉我这是否真的是一个坏主意,那就是要有一个包含这些随机字符串的表。该表将如下所示:

| submissionId | stringId 
+--------------+----------
| 1            | rbMZV    
+--------------+----------
| 2            | MQyPi    
+--------------+----------
| NULL         | hfXL7

生成这些字符串时,它们没有分配submissionId,例如我的示例表中的“ hfXL7”。当用户提交提交时,我的脚本将采用第一个随机生成的字符串,该字符串尚未分配submittionId,并将在提交该提交时生成的submittionId添加到该记录。我在某个地方有一个过程,该过程会定期生成更多字符串,当人们进行更多提交时可以使用这些字符串,因此当有人进行提交时,总是至少会有一个随机生成的字符串,而没有submittionId。

6 个答案:

答案 0 :(得分:3)

这是三种基本方法:

  1. 预先生成并存储所有随机ID-数量足够多,以至于它们永远不会用完(给定预计的总使用次数)。这里的一个缺点是,可能很难预测支持系统寿命所需的ID总数。
  2. 生成足够数量的随机ID,以在设置的时间段内提供足够多的随机ID。然后定期生成足够的新内容以满足预期的需求。 (例如,时间段可能是一天,并且发电机可能被安排在需求低迷的夜晚的某个时间点运行。)
  3. 仅在需要时动态生成随机ID。

每种都有优点和缺点:

  • 如果存储不是问题,(1)也许是最简单的选择,因为它一旦完成就可以永久保存-您不必担心失败的工作等。
  • (2)基本上是您建议的方法:看起来不错,但是还有更多需要考虑的事情,例如不可预测的使用高峰,计划的作业失败等。
  • (3)可能也很简单,并保持精简,因为表格会随着时间的增长而增长,因此无需预测用法。潜在的不利之处在于,任何此类函数都会一直生成ID,直到找到唯一的ID,因此,随着ID数量的增加,它可能会变得更慢-尽管只要不同随机排列的数量为0,这可能永远不会成为问题。大大超过潜在的使用总数。

上述方法(3)的演示

如何在MySQL中实现即时生成器的在线演示:http://rextester.com/TKGPZ41053

排列数计算

如果区分大小写字母数字,则总共有62个不同的字符。因此,每种长度的可能排列数目如下:

Characters | Permutations
1          | 62
2          | 3844
3          | 238328
4          | 14776336
5          | 916132832
6          | 56800235584
7          | 3521614606208
8          | 218340105584896
9          | 13537086546263552
10         | 839299365868340224

答案 1 :(得分:1)

就像汉斯·帕森特(Hans Passant)在评论中说的那样,一种简单的策略是对URL中自动递增的主键进行base64编码。

此方法的一个更安全的变体是使用分组密码对您的主键值进行加密,然后对结果进行base64编码(在URL中)。这具有固定长度值的优点。

我已在项目中成功使用Skip32(Skipjack算法的一种变体)。

答案 2 :(得分:0)

这实际上取决于首先不使用PK的目的以及这些合成版本需要使用多长时间。

尽管您仍在进行生成和检查唯一值的工作,但您提出的建议是可以的。除了找到未使用的代码外,我可能会提前生成submissionId和代码。两个并发的数据库访问都将找到相同的“未使用”行(或相互阻塞,这取决于您如何实现)。都不是很好,也不是必需。

您还可以对行中的PK或PK +其他[不可变]元素进行加密。在网络世界中,您可能会使用会话获取临时代码,并且可能使用每个用户唯一的代码。这真的取决于目的。

答案 3 :(得分:0)

我会尝试一些稍有不同的事情,并避免在所有随机物品填满之前填写表格。我将有一个包含以下列的表格:

CREATE TABLE [dbo].[Links]
(
    [Id] [bigint] IDENTITY(1,1) NOT NULL
  , [StringId] [nvarchar](5) NOT NULL
  , [OtherInfo] [<whatever type you need]
  , CONSTRAINT [PK_LinksId] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )
)

Id列作为群集主键将有助于维持插入率。

然后,我将在StringId列上添加唯一索引以进行快速查找。由于您不会寻找部分StringId而是寻找完整的CREATE UNIQUE NONCLUSTERED INDEX [IDX_StringId] ON [dbo].[Links] ( [StringId] ) ,因此索引应该提供必要的速度。

Auto Update Statistics Asynchronously

如果以某种方式两次生成相同的stringId,SQL将捕获它,您将能够生成另一个随机字符串。

为避免任何意外的变慢,我还考虑将true设置为IDX_StringId,以便在统计信息过时并需要更新时不会阻止查询。

最后,需要计划维护,以确保{{1}}索引不会变得过于分散。 Microsoft在下面的address中提供了一个存储过程,该存储过程可以每晚运行。

答案 4 :(得分:0)

我质疑你的主张

  

并确保在用户发送提交内容时尚未使用随机生成的字符串,这会随着时间的推移降低表的速度

SQL索引(唯一索引或其他索引)通常存储在B-Trees中,因此它会变慢,但是直到您超出可以完全加载到服务器RAM中的索引记录的数量时,这种情况才会明显(这会超过uint32.max条记录)。此时,您可以升级服务器或仅实施sharding策略。

在您想像的规模上,并发(例如部分提到的@LoztInSpace)将是要解决的难题。但是,对于几乎我能想到的任何流量级别,仍然可以使用乐观的插入以及适当的分片级别

答案 5 :(得分:0)

您需要随机生成的通用/全局唯一标识符,并且大多数数据库为此提供了内置函数。newid()和newsequentialid()是T-SQL提供的两个函数,可用于唯一标识您的行。

INSERT cust  (CustomerID, Company, Fax)  VALUES   (NEWID(), 'Wartian Herkku','981-443655'); 

如果您决定使用它,我建议使用newsequentialid()而不是newid(),原因为performance benefit of seq id