【问题标题】:Unique url from primary key来自主键的唯一 url
【发布时间】:2012-08-17 01:22:50
【问题描述】:

我正在尝试创建一个在外观和行为上类似于 youtube 的 /v=xxx 的 URL。简而言之,用户将上传文件并能够通过该 URL 访问它们。此 URL 代码需要是某种形式的数据库主键,以便页面可以收集所需的数据。我是数据库新手,这更像是一个数据库问题。

在我的数据库中,我有一个自动递增的主键,用于访问文件数据。我想使用该号码来创建文件的 URL。我开始研究不同的哈希函数,但我担心冲突。我不希望两个不同的文件使用相同的 URL。

我还考虑使用uniqid() 作为我的主键CHAR(13),直接使用它即可。但有了这个,我担心效率。另外环顾四周,我似乎找不到太多关于它的信息,所以这可能是一个奇怪的想法。更不用说在生成 id 时我需要测试冲突,这可能是低效的。自动增量要容易得多。

有什么好的解决办法吗?我的任何一个想法都会奏效吗?如何从自动递增的主键生成唯一 URL 并避免冲突?

我倾向于我的第二个想法,它的效率不会很高,但是当需要将东西添加到数据库(测试冲突)时会导致最大的性能缺陷,这对于最终用户来说只会发生一次。另一个性能缺点可能是实际查找字符而不是整数。但我主要担心这是不好的做法。

编辑:

一个简单的解决方案就是直接使用自动递增的值。叫我挑剔,但这看起来有点难看。

【问题讨论】:

  • 您预计将拥有多少条记录?
  • 为什么你认为使用自增值很难看?
  • @sberry 这真的取决于,从一开始就不多。但我想值得注意的是,文件将在 2 个月后被删除。因此,一次不要超过几千个。
  • @Briguy37 我的意思是 URL 很丑,www.example.com/id=123 对我来说似乎很奇怪,仅此而已
  • 我有点困惑,因为它与您想要的 YouTube 示例网址 /v=xxx 的格式相同。如果你想要 id 中的字母,你总是可以将 id 转换为十六进制或自定义的字母数字系统,并从一个看起来不错的值开始 id 计数。

标签: php mysql primary-key


【解决方案1】:

生成不冲突的短哈希确实会让人头疼。因此,相反,Stackoverflow 的 slug 格式非常有前途,并且可以保证生成不重复的 url。

例如,同样的问题有

https://stackoverflow.com/questions/11991785/unique-url-from-primary-key

在这里,它具有唯一的主键和一个标题,使其更加 SE 友好。


但是,正如评论所言,他们之前提出的问题很少,可能会清楚,为什么?您正在尝试的内容最好省略。

  1. How to generate a unique hash for a URL?
  2. Create Tinyurl style hash

创建短散列会大大增加冲突的机会,因此更好的用户 base64sha512 使用函数来创建安全散列。

【讨论】:

  • 你说得对,但这不是他要求的。他也可以只使用主键(数字),但他需要一个带字符的短网址。
【解决方案2】:

您可以简单地对时间进行哈希处理,然后检查该哈希(或您的数据库中该哈希的一部分。 如果您在数据库中的该字段上设置索引(并确保散列足够长,不会产生很多冲突),那么它在任何时候都不是问题。

<?php

$hashChecked = false;

while( $hashChecked === false ){
  $hash = substr( sha1(time().mt_rand(9999,99999999)), 0, 8);  //varchar 8 (make sure that is enough with a very big margin)
  $q = mysql_query("SELECT `hash` FROM `tableName` WHERE `hash` = '".$hash."'");
  $hashChecked = mysql_num_rows() > 0 ? false : true;
}

mysql_query("INSERT INTO `tableName` SET `hash` = '".$hash."'");

【讨论】:

  • 你的 while 循环永远不会打破它,你会遇到冲突,并且为每个插入进行选择是不必要的开销。
  • 你说得对,我改了代码。避免“开销”的唯一方法是使用自动增量字段。
【解决方案3】:

如果您愿意使用随机数来生成短 URL,这非常简单。例如,您可以这样做:

 SELECT BASE64_ENCODE(CAST(RAND()*1000000 AS UNSIGNED INTEGER)) AS tag

这能够为您提供一百万种不同的标签。要获得更多可能的标签,请增加与 RAND() 数相乘的值。这些标签值将难以预测。

为确保不会出现重复项,您需要对标记值进行重复数据删除。这很容易做到,但需要您的程序中的逻辑。将标签值插入到使用它们作为主键的表中。如果插入失败,请重试,重新调用 RAND()。

如果您接近标签的最大数量,您将开始遇到大量插入失败(标签冲突)。

BASE64_ENCODE 来自您需要安装的存储函数。你可以在这里找到它:

http://wi-fizzle.com/downloads/base64.sql

如果您使用的是 MySQL 5.6 或更高版本,则可以使用内置的 TO_BASE64 函数。

【讨论】:

    【解决方案4】:

    我想做一些类似的事情(但用文章,而不是上传的文档),并想出了一些不同的东西:

    • 取一个质数 [y](远)大于文档的最大数量 [n](例如,25000 足以容纳文档总数,而 1000099 是一个比25001)
    • 对于当前文档 id [x]:(x*y) 模数 (n+1)
    • 这将生成一个介于 1 和 n 之间且永不重复的数字

    虽然 url 可能看起来像一个传统的主键,但它确实有一点优势,即每个后续文档都有一个与前一个文档完全无关的 id;也有人争辩说,不包括主键也有非常轻微的安全优势……

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 2011-09-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多