MySQL在实际场景应用中的问题和思路

来源:互联网 发布:什么日语翻译软件好 编辑:程序博客网 时间:2024/05/18 13:10

1、分表

分为横向分表和纵向分表,横向分表直观来说即画一条水平线将大表分成若干个子表,每个子表的字段是相同的;纵向分表偏向于按照业务逻辑分表,每个子表有不同的字段。

举例来说,现有用户表:t_user,记录注册登录信息(字段有username,password等),记录个人信息(字段有realname,idcard等),记录用户订单信息(字段有order,status等)。

首先进行纵向分表,按照业务逻辑将用户表拆成三张表:注册登录信息表、个人信息表、订单表。每张表都包含UID字段,根据UID作为表的CURD条件。

纵向分表的好处是,避免大表数据稀疏。比如100人注册,完成填写个人信息有50人,但真正下单只有1个人,这样50行数据的个人信息相关字段、99行的订单信息相关字段都为空。但分表后也会使原本一条SQL即可查询到的信息要用3条SQL才能查询到,所以这里强调纵向分表需要按照业务逻辑分表,即登录接口不需要获取订单信息,订单接口也不需要验证登录信息,才会认为这种分表处理是合理的。

然后随着用户数量继续增加还会进行横向分表,如根据UID尾数将1张表分为10张表:user_base 拆成 user_base_0 ~ user_base_9,横向分表后可以有效解决单表数据量过大问题,但查询条件非UID时,应用层完成一次查询,底层需要查询10张表(union操作)。所以需要从实际业务角度出发,保证绝大多数的操作是以UID作为条件的,这样只需查询指定的一张表即可。

其他分表规则,还可能按照更新频率进行分表,为读而设计的索引可能并不利于数据写入,将主要用来读的数据和用来写的数据分成两张表,提高查找、更新效率。

同时,分表后会使JOIN操作无法进行,如原来 user_info 和 user_order 表可以做连接查询,但是分表后每张表被拆成了10张子表,JOIN操作即无法使用。该问题没有较完美的解决办法,目前的处理方式是,业务上尽量避免这种需求,如果数据分析需要使用,将分表重新合成一张大表单独放置,即分表用来支持业务需求,大表用来支持数据需求。

2、数据抽象

在数据保存时即对数据进行初步加工和抽象,将多个字段汇总成一个字段。

举例说明,如要判断用户基本信息是否填写完成,一般做法依次去判断数据库的姓名、手机号、身份证等等诸多信息是否完成,全部完成则认为基本信息完成可以进行下一步操作。

另一种做法是将这些信息统一抽象成一个字段专用于判断权限:user_status,只有完成和未完成两种状态,每次判断不需要读取以上那些信息,只需要检查这一个字段即可。

优势是简化了判断条件,很好满足了这种实际业务需求:用户只需一次填写,但用户使用操作中频繁校验。另外对数据实时性要求不高的情况下,可以以定时跑脚本的方式,检查用户信息完成情况并更新相应状态。

缺点是对数据的一致性高,用户信息保存失败等情况要保证状态不发生更新,需要使用事务操作。

3、用行代替列进行储存

此条应用场景具有局限性,如果表中的列有增加的可能,则考虑用改用行储存。举例用户一笔订单中包含ABCD四项费用,正常来讲数据表应如下设计:

id uid feeA feeB feeC feeD 1 1001 100 100 100 100 2 1002 200 200 200 200


但可能从某一天开始,需要向用户收取E费用,此时需要为表添加字段。如果该表数据量已经很大,添加字段的工作则难以进行,而且随着业务场景变动,可能还会添加F、G、H等费用,此时则需要考虑用行代替列进行储存,新数据表如下:

id uid fee price 1 1001 A 100 2 1001 B 100 3 1001 C 100 4 1001 D 100 5 1002 A 200

(省略…)

这种做法好处显而易见,非常便于字段的扩展;但缺点不便于查询,效率上不如前一种方式,通常会为查询条件(如UID)加索引,来提高查询效率。
DBA认为这种“用行代替列进行储存”的数据表单表能够支持亿级别的数据。

其他扩展字段的办法是预先设置 extra_info 这种字段,将要保存的信息转为Json格式存入该字段中,但是代价是非常不便于查询,如果需要以Json内部字段作为条件查询时,只能通过脚本全表遍历,且查询时需要判断字符串相等,匹配效率本身较低。

如果已经产生了这种Json数据,需要向新表做数据迁移,办法通常为:通过脚本遍历解析旧数据,写入新表;脚本运行过程中的数据,进行双写,即一份数据同时写入两张表里;脚本运行完成后停止双写。

4、后端数据打点监控储存

便于监控系统状态、便于追查问题。在关键接口调用时应当做记录,写入指定的log表中,记录内容:who/when/what/result,即谁?什么时候?做了什么?结果是什么?

使用接口打点而非日志分析的原因是:人工分析日志效率低,自动分析日志对格式要求较高,且两者实时性和可靠性均没有打点统计高。

5、一些建议
数据库字段类型不要使用枚举类型enum。

Json只用来保存临时的、重要性不高的数据。很可能在设计时认为这里用Json保存没关系,但后来需求变动,需要对Json内部的字段进行处理,这样会十分不便。(举例:身份证正反面OCR信息,最开始放到Json中保存,后来需要校验OCR数据以更新认证状态,只能使用脚本全表扫描解析Json)

不重要或使用频率非常低的信息,但是数据量很大,可以考虑不使用MySQL,使用HBase等代替。(举例:用户硬件设备信息,传感器信息等)

阅读全文
0 0