mysql – 搜索长字符串的SQL性能

我需要将用户代理字符串存储在数据库中,以便跟踪和比较不同浏览器之间的客户行为和销售业绩.非常简单的用户代理字符串长度约为100个字符.决定使用varchar(1024)来保存数据库中的useragent数据. (我知道这是矫枉过正,但这就是想法;它应该适应未来几年的使用者数据,一些设备,工具栏,应用程序已经推送了500个字符.)保存这些字符串的表将被规范化(每个不同的用户)代理字符串只会被存储一次)并被视为缓存,因此我们不必一遍又一遍地解释用户代理.

典型的用例是:

>用户来到我们的网站,被检测为新的游客
>为此用户创建新会话信息
>确定我们是否需要分析用户代理字符串,或者我们是否对文件进行了有效分析
>如果我们拥有它,那么很好,如果没有,请分析它(目前,我们计划调用第三方API)
>将相关信息(浏览器名称,版本,操作系统等)存储在连接表中,将现有用户会话信息绑定并指向缓存条目

注意:我倾向于在数据库中说“搜索”用户代理字符串,因为它不是一个简单的查找.但要明确的是,查询将使用’=’运算符,而不是正则表达式或LIKE%语法.

因此,查找用户代理字符串的速度至关重要.我已经探索了一些方法来确保它具有良好的性能.由于大小原因,将整列索引是正确的.部分索引不是一个好主意,因为大多数用户代理最终都有区别信息;部分索引必须相当长才能使其值得,因为它的大小会导致问题.

所以它归结为哈希函数.我的想法是在Web服务器代码中散列用户代理字符串并运行select以查找数据库中的散列值.我觉得这样可以最大限度地减少数据库服务器上的负载(而不是让它计算哈希值),特别是因为如果找不到哈希值,代码就会转向并要求数据库再次计算插入的哈希值.

散列到整数值将提供最佳性能,存在更高冲突的风险.我期待最多看到数千或数万用户代理;甚至100,000个用户代理也能很好地适应2 ^ 32大小的整数,只有很少的冲突,可以通过Web服务解密,而性能影响最小.即使您认为整数哈希不是一个好主意,使用32字符摘要(例如SHA-1,MD5)对于选择应该比原始字符串快得多,对吧?

我的数据库是MySQL InnoDB引擎. Web代码将首先来自C#,稍后将来自php(在我们整合一些托管和身份验证之后)(并不是说Web代码应该有很大的不同).

如果您认为这是一个蹩脚的选择我的哈希算法问题,请让我为此道歉.我真的希望从之前做过类似事情的人和他们的决策过程中获得一些意见.那么,问题是:

>您将为此应用程序使用哪个哈希?
>你会在代码中计算哈希值还是让db处理它?
>在数据库中存储/搜索长字符串是否存在完全不同的方法?

最佳答案 您想要散列长字符串以创建在商店(缓存或数据库)中查找的令牌是一个很好的想法.我已经看到这对于非常大的字符串,并且在高容量环境中已经完成,并且它工作得很好.

“你会在这个应用程序中使用哪个哈希?”

>我认为加密(哈希)算法并不重要,因为您没有哈希来加密数据,您正在进行哈希创建一个令牌,在该令牌上用作查找更长值的键.因此,散列算法的选择应基于速度.

“你会在代码中计算哈希值还是让数据库处理它?”

>如果是我的项目,我会在应用层进行散列,然后将其传递给在商店内查找(缓存,然后是数据库).

“在数据库中存储/搜索长字符串是否存在完全不同的方法?”

>正如我所提到的,我认为,出于特定目的,您提出的解决方案是一个很好的解决方案.

表推荐(仅限说明):

用户

> id int(11)unsigned not null
> name_first varchar(100)not null

user_agent_history

> user_id int(11)unsigned not null
> agent_hash varchar(255)not null

代理人

> agent_hash varchar(255)not null
> browser varchar(100)not null
>代理文本不为空

关于架构的几点注意事项:

>从您的OP看起来您需要用户和代理之间的M:M关系,因为用户可能在工作时使用Firefox,但随后可能会在家中切换到IE9.因此需要数据透视表.
>用于agent_hash的varchar(255)可供讨论. MySQL suggests使用varbinary列类型来存储哈希值,其中有几种类型.
>我还建议将agent_hash作为主键,或者至少为列添加UNIQUE约束.

点赞