mysql - 将 User-Agent 字符串的哈希存储在 MySQL 表中 : insert if not exists, 返回 id

标签 mysql sql indexing insert duplicates

受 stackoverflow 上以下两个答案的启发,我尝试实现一个表,目标是在其中存储 User-Agent 字符串:

这是我的表结构:

CREATE TABLE IF NOT EXISTS ua_strings (
    ua_id INTEGER PRIMARY KEY AUTO_INCREMENT, 
    ua_hash BINARY(16), 
    ua TEXT, 
    UNIQUE KEY ua_hash (ua_hash)
);

我想实现以下目标:

  • 输入:User-Agent 字符串,只有当它不存在时才应该插入到表中

  • 输出:ua_id

到目前为止,我想出了这个解决方案:

INSERT IGNORE INTO ua_strings (ua_hash, ua) VALUES (UNHEX(MD5('test')), 'test');
SELECT ua_id FROM ua_strings WHERE ua_hash = UNHEX(MD5('test'));
  • 是否可以从这两个查询中进行一个查询?
  • 如何在速度和优雅方面改进表结构或查询?

最佳答案

最重要的是摆脱INSERT IGNORE。我发现即使失败也会增加主键。您可以通过这种方式快速烧掉 40 亿个 key 。首先执行 SELECT,这将是最常见的情况。

我的第一个想法是将逻辑放入数据库函数中。这为您提供了封装的所有好处。然后您可以稍后更改它的工作方式。

我的第二个目标是摆脱那个散列。它有效地取代了 ua 上的索引。由于您只需要等价检查来提高性能,因此哈希索引是理想的选择,但大多数 MySQL 表格式不支持这些索引。

我会在用户代理的前 255 个字节上使用一个索引,这应该足以让 MySQL 完成它的工作。如果您需要做的不仅仅是简单的获取,这还可以为您提供完整索引的好处。

CREATE TABLE IF NOT EXISTS ua_strings (
    ua_id INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT, 
    ua TEXT,
    KEY(ua(255))
);

函数看起来像这样(注意,我不是最擅长编写 MySQL 函数的)。

DELIMITER //
CREATE FUNCTION get_ua_id (ua_string TEXT)
RETURNS INTEGER
BEGIN
    DECLARE ret INTEGER;

    SELECT ua_id INTO ret FROM ua_strings WHERE ua = ua_string;

    /* It's not in the table, put it in the table */
    CASE WHEN ROW_COUNT() = 0 THEN
        INSERT INTO ua_strings (ua) VALUES (ua_string);
        SELECT LAST_INSERT_ID() INTO ret;
    ELSE BEGIN END;
    END CASE;

    RETURN ret;
END//
DELIMITER ;

具有散列的函数看起来非常相似。隐藏函数中的实现细节并对两者进行基准测试。

并且真的不要使用 MD5。使用 SHA1 不会影响性能,您可以为每个条目留出额外的 4 个字节,这将避免隐藏的问题。使用 MD5 就像在说“尽管有更好的锁,但我还是会使用这把破锁,因为我认为这扇门现在不重要”。您不是安全专家(我也不是),不知道哪些部分重要哪些不重要。只需对所有内容进行适当的锁定即可。如果 SHA1 被证明是一些巨大的性能问题,您可以随时更改它,这要归功于函数的封装。

无论基准测试结果如何,我敢打赌,分析将揭示您的选择对它所属的任何系统的性能没有影响。使用更简单、更灵活的索引选项,如果以后出现问题,请对其进行优化。

关于mysql - 将 User-Agent 字符串的哈希存储在 MySQL 表中 : insert if not exists, 返回 id,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29088515/

相关文章:

mysql - 从 "log"表获取数据到 mySQL 查询

mysql - 当主表与另一个多对一关系表连接时,字段的 SUM 相乘

mysql - SQL DDL : Recursive table with two foreign keys (MySQL)

arrays - Matlab 不使用循环创建新的值数组

python - 在数据框上标记索引

mysql - 如何通过邮政编码将一张表连接到另一张表?

mysql - 为什么我的查询没有显示错误,但也返回零行?

MySQL插入带日期的行

mysql - 当表2值不存在时,从表1中获取记录并从另一个表中加入它

c# - 如何在 C# 中使用索引从多图标 (.ico) 文件访问图标