【问题标题】:Database table with two possible unique keys具有两个可能的唯一键的数据库表
【发布时间】:2021-10-26 22:23:08
【问题描述】:

我有一张桌子,我正在努力弄清楚如何最好地构建它。它应该包含一堆文件的元数据,对于每个文件,我们都有以下信息:

  • 文件名
  • 文件大小
  • 上次修改
  • md5(有时)

我希望唯一键位于 md5,但如果 md5 是 NULL,我希望它回退到 filename+filesize。是的,文件名+文件大小不是完美匹配,但根据我所做的分析,它的准确率约为 99.9%,而且对于超过 24 个字符的文件名,准确率几乎为 100%。

存储此密钥的最佳方式是什么?我应该添加一个应用生成的列(或触发器?)类似于:

COALESCE(md5, CONCAT(filename, filesize))

或者这种“多键”的事情在实践中通常是如何完成的?

【问题讨论】:

  • md5 是从哪里来的,你能手动创建缺失值并在缺失时添加插入吗?
  • @Stu 不,这是资产的 md5——我通常无权访问该文件,有时我可以,但文件很大,需要很长时间才能生成(~100GB 视频)。
  • 出于性能原因,我会坚持使用一个主键。我遇到了复合键的问题,包括空值。
  • @RaphaelPICCOLO 你建议怎么做?触发器?在插入之前的应用程序中?等
  • 我认为要给出有用的答案,您应该详细说明您的应用程序。当您尝试插入一条已经存在 md5 的新记录时会发生什么?这不可能发生;或者如果文件名和大小不同,则替换记录?你给个错误?忽略操作?类似地插入 md5 为空的记录。

标签: mysql sql database-design primary-key


【解决方案1】:
filesize BIGINT UNSIGNED NOT NULL,
md5 BINARY(16) NULL,
PRIMARY KEY(id?)  -- UNIQUE
INDEX(filename, filesize),  -- or UNIQUE?
UNIQUE(md5)    -- ok to have multiple NULLs

( SELECT ...
    WHERE md5 = UNHEX(?) )
UNION ALL
( SELECT ...
    WHERE filename = ?
      AND filesize = ? )
ORDER BY md5 DESC      -- give preference to non-NULL
LIMIT 1                -- Either the md5 one or some one with the desired size

是的,一个表可以有多个唯一键,但这种情况很少见。这通常是架构设计不佳的标志。

我避免使用COALESCE(),因为它不可分割,因此很慢。上面的代码将是两个快速索引查找,然后是一个简单的排序。

【讨论】:

  • 谢谢。出于好奇,您为什么将 md5 存储为 BINARY(16) 而不是 CHAR(32) ?
  • @David542 - 占用了一半的空间。但是,它确实需要应用程序代码来执行 UNHEX()HEX()。对于笑容,我曾经使用过 Base64 和 CHAR(22) COLLATE ascii_bin。这是SELECT * 的可读性和节省一些空间之间的折衷。
【解决方案2】:

我会选择 2 个键(都是非唯一的):

  • 你的 md5 列上的一个键
  • 以及文件名 + 文件大小的键

加上一个正常的自增主键

当你执行 sql 查询时,mysql 会自动决定使用哪个索引。

所有 thos 3 请求都应该有效。您还可以在 select 查询前面添加 explain 关键字来检查索引使用和瓶颈。

explain select * from files where md5 = 'xxx';
explain select * from files where filename = 'xxx' and size = 'xxx'
explain select * from files where md5 = 'xxx' or (filename = 'xxx' and size = 'xxx')

【讨论】:

  • 违背了整个目的...两个键都必须是唯一的(除非它们为空)
  • 理论上,2个文件可以有相同的内容,那么相同的md5对吗?独特的约束会阻止这种情况。如果你愿意,你可以做一个独特的约束
  • 我认为您是在建议如何提高查询性能(因此解释),我不关心查询,我只关心完整性和架构。
  • 如果你想让它工作,你不应该在 md5 列中使用空值。那么你有一个 3 列的唯一键。这是对空值的解释。 stackoverflow.com/questions/3086382/…
  • 带有OR 的那个将进行全表扫描。
【解决方案3】:

你的逻辑很好, 我只会进行简单的调整,让 ID 列是自动递增的,并且对于每一行都不为空,如果可能的话,我会根据它来做唯一键

建议 -> concat(ID,"",md5,"",concat(filename, filesize))

Picture

这样你就可以确保每一行都有唯一的键,

几乎唯一对数据建模没有帮助,您说您有 99.9% 的准确率,这意味着有多个唯一键,这对 ER 模型不利,并且当通过该键连接表时,它可以使很多- 许多连接和复制数据。

希望对你有所帮助^^

【讨论】:

  • 感谢您的建议,但是将 ID 放在合并的开头会自动使每一行的值成为该值。你的意思是放在最后吗?
  • 另外,您将在何时/何地填充该构造键?在触发器中?在应用程序中插入之前?还是在哪里?
  • @finally -- 为什么合并中的额外" "?合并的目的不是获取第一个非空值吗?
  • 嘿,它可以在触发器中,通常我用 ETL 做,但是当你拥有所有符合特定条件的数据时,你可以添加新列,先形成表格,然后添加新列这将根据您的决定生成密钥:)
  • 看更新的图片,我认为应该如何,在这个视图中它没有显示好的格式
猜你喜欢
  • 1970-01-01
  • 2013-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-24
  • 2021-03-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多