具有两个可能的唯一键的数据库表
Posted
技术标签:
【中文标题】具有两个可能的唯一键的数据库表【英文标题】: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 为空的记录。 【参考方案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 列的唯一键。这是对空值的解释。 ***.com/questions/3086382/… 带有OR
的那个将进行全表扫描。【参考方案3】:
你的逻辑很好, 我只会进行简单的调整,让 ID 列是自动递增的,并且对于每一行都不为空,如果可能的话,我会根据它来做唯一键
建议 -> concat(ID,"",md5,"",concat(filename, filesize))
Picture
这样你就可以确保每一行都有唯一的键,
几乎唯一对数据建模没有帮助,您说您有 99.9% 的准确率,这意味着有多个唯一键,这对 ER 模型不利,并且当通过该键连接表时,它可以使很多- 许多连接和复制数据。
希望对你有所帮助^^
【讨论】:
感谢您的建议,但是将ID
放在合并的开头会自动使每一行的值成为该值。你的意思是放在最后吗?
另外,您将在何时/何地填充该构造键?在触发器中?在应用程序中插入之前?还是在哪里?
@finally -- 为什么合并中的额外" "
?合并的目的不是获取第一个非空值吗?
嘿,它可以在触发器中,通常我用 ETL 做,但是当你拥有所有符合特定条件的数据时,你可以添加新列,先形成表格,然后添加新列这将根据您的决定生成密钥:)
看更新的图片,我认为应该如何,在这个视图中它没有显示好的格式以上是关于具有两个可能的唯一键的数据库表的主要内容,如果未能解决你的问题,请参考以下文章