我有一个DB列(类型varchar(255)
),该列存储SecureRandom.urlsafe_base64
生成的URL安全的base 64字符串。方法调用使用默认值,因此结果应为16 bytes or 22 characters in length。
base64值用于在用户访问站点时查找记录,以掩盖数据库ID。由于此查找,我需要为该列创建索引,但是我不想为整个列建立索引,因为可能在存储方面效率很低。
确定在这种情况下使用的最佳索引前缀的最佳方法是什么?我现在在想的是这样的:
EXPLAIN
,以查看有多少
记录需要检查这里的问题是我知道SecureRandom
会生成唯一的基数为64的字符串,但我不确定它们是多么独特。例如,在10万条记录中,如果我使用8个字符的前缀,那么该前缀将由10条记录或100条记录共享吗?
关于我的方法的一些更具体的问题:
注释:
SecureRandom
来自Ruby SecureRandom
的URL安全功能没有改变base 64输出的唯一性特征。答案 0 :(得分:0)
这只是一个随机数,对吗?不加密。
不要不使用前缀;尽管它会缩小索引的大小,但在许多情况下会使索引的使用无效。的确,22个字节长于8个字符的字符串或4个字节的INT
。但是,无法使用该索引的不利条件更加严重。
默认值为16(22)足以使随机字符串具有唯一性,从而避免意外碰撞。
如果最大值为22,请不要说VARCHAR(255)
。如果是固定长度,请说CHAR(22)
,如果您允许用户选择最大为16的长度,请说VARCHAR(22)
。
针对该列说CHARACTER SET ascii COLLATE ascii_bin
。这样可以避免(1)utf8的开销和(2)大小写折叠的错误。
如果您要为十亿个此类项目建立索引,则将存在重大的性能问题,如here所述(尽管在不同的上下文中)。一百万行可能不是问题-它取决于索引何时变得大于可以在buffer_pool中的RAM中缓存的索引。
(如果我没记错的话,对于您所描述的8个字符,在300K中有一个机会,一个包含300K条目的索引将包含重复项。但这不是问题。)
答案 1 :(得分:0)
我决定按照我在问题中概述的步骤进行操作。结果,我得到了选择索引前缀所需的信息。
此实验产生了两个变化:
255
减小到22
(也由@Rick James建议)。有关数据为何不超过22个字符的问题,请参阅问题中的详细信息。我测试了长度为1、2、4、8和16个字符的前缀,并使用EXPLAIN
来查看列中的查找将执行的操作。我还测试了没有索引作为基准。我的实验是基于一组10万条记录。我本可以用更多的记录进行测试,但是出于我的目的,没有必要变得更加精确。
以下是实验的重点:
SecureRandom
列上的查询将进行表扫描。除了4个字符的前缀之外,还有一个100k的数据集,并且基于SecureRandom.urlsafe_base64
的特征,我无法得到更精确的结果。根据生产中表格的当前大小以及对表格增长率的粗略了解,我们决定将8个字符的前缀用于未来,同时节省磁盘和内存使用。
通过这次探索,我还了解了MySQL的索引选择性功能。这将允许使用相同的100k记录样本集来测试针对每个前缀长度检索到的记录数,而不必在每次测试之前运行迁移来添加/删除不同的索引。例如,要测试4个字符的前缀的选择性,请执行以下操作:
SELECT count(*) AS count, LEFT(uuid_column, 4) AS prefix
FROM string_prefix_test GROUP BY count DESC LIMIT 10;
有关索引选择性的更多详细信息,请参见2012年版的高性能MySQL (第160页)。
接下来,我将研究varchar
列索引的前缀,这些索引的数据不具有SecureRandom.urlsafe_base64
的唯一性。仅因为获取具有代表性的数据集比较困难,这将更具挑战性。