最近给我提建议的陌生人是不少,有提示我对于云费用计算常识性错误的,有对我 OB 的撰写方式异议的,还有一个陌生人,在看完我的文字后,留言:你也是做自媒体的,你自己的排版太差,你自己知道吗,你这样让我影响阅读。
从人性上讲,人都是站在自己的角度上来看问题,这是最普通和正常的,基于自己的角度看问题,就都是自己合适,自己认为理所应当。那么我在知道自己的排版很烂的情况下还这样的原因:
人的精力都是有限的,我要做我自己的工作,同时要管理我的团队,并且还要有各种团体来找我做一些事情,我的文章的确是排版有问题,但这是我精力和认知范围内,目前能做到的程度。
同时也谢谢这位同学,我也有一个建议,建议你也在给出意见的同时,给一个解决的方案,如果你是希望别人也进步是你的初衷的情况下。
正文
数据库的开发人员工作并不容易,无论他们使用的是SQL SERVER , ORACLE, DB2, MYSQL, POSTGRESQL还是 SQLLITE ,这些数据库有相同的挑战,就是语句的执行效率,如果语句撰写的不佳,则会导致更多的系统的资源的浪费,或未充分的利用数据库提供的有限资源,而需要扩充更多的资源来应对自己的SQL 不良产生的更多的资源的需求。
这里总结了在编写应用程序是要避免的七个常见的陷阱。
1 在近似的业务逻辑中,盲目的重用SQL语句
2 嵌套视图
3 在单个事务中进行大型的超多表的操作
4 选择错误的列产生主键
5 通过判断行数来检查数据是否存在
6 使用触发器
7 做反向查询,使用排除思维的方式
1 重用SQL
这点在开发中经常存在,基于对于业务的理解的不准确与描述的问题,这里开发会将自己写好的业务的SQL进行分类,这里在提到某一种查询的时候,会自动将原来写好的SQL,进行添加和改变后,再次使用,这里有一些问题, 原有的SQL 本身有一些表并不是现有的表需要的,或者一些条件的过滤并不细致,等等,或查询的中一开始并未过滤有效数据,而是到了后面在进行过滤的情况等等,这些都会导致重用SQL 浪费资源的问题,并且这样的SQL还带有由于SQL中存在不需要的条件,不需要的表导致的SQL 的逻辑与原有定义的逻辑不符导致的查询逻辑错误的问题等。
2 嵌套视图
在应用程序查询中,为了便于将一些固定的查询语句成为一个基板,方便调用,很多应用程序中就使用了大量的视图VIEW来解决问题,这固然是好的,但是在查询中,大量使用视图调用,这样的方式并不可取,这里会有一些问题存在,首先视图并不是为所有的查询而产生的,所以这里在调用的时候,会产生冗余数据库的可能,同时也有可能会产生检索的数据不够的问题,并且添加其他的语句来完成,而如果VIEW进行改变,则影响的连带性就是一个灾难,在你针对一个视图的改变后,可能会引起你不知道的查询的数据错误,逻辑错误,查询执行计划与查询性能的问题等,所以不要在查询中,嵌套视图作为查询的对象。
3 多表JOIN条件过滤在最外部的语句
在SQL的语句撰写中,基于以下的一些原因,导致在查询中语句撰写需要多个表来参与,最终导致一些7-8个表 10 -15个表在一起进行数据联合查询的方式,并且这些查询中还只是OLTP的操作行为,引起这些查询产生的原因有
3.1 表设计严格按照三范式的方案来进行,但是业务逻辑复杂,先期并未对于表进行良好的规划,导致一个业务逻辑获取数据,需要多个表参与才能获得数据。
3.2 基于开发人员对于数据原子写的观念问题,希望写入数据写入的时候,只是针对一张表,而不是同样的数据写入到多张表中,基于惧怕写入数据的事务过大的问题,导致核心的数据仅仅存在一个表中。基于这种理念导致一些复杂的查询需要引入多个表参与进行数据查询
3.3 业务逻辑定位不清,导致早期表设计混乱,本来一张表可以表达的事情,分散到多张表进行表达,引起查询一次简短的信息也需要多张表参与。
3.4 撰写多表混合查询的语句时,把数据过滤的部分都写到了表链接外部,虽然这样撰写能保证业务逻辑的完整和正确,但是这样的操作方式,也会给如MYSQL 这样的数据库在一开始加载大量的数据不能进行过滤,导致缓存和CPU高消耗的情况下,导致慢查询等发生。
4 主键的选择错误的问题
在一些数据库中,主键的选择是一个学问,这里尤其在MYSQL的主键选择和使用中,主键的使用是要注意的。这里有一些需要注意的问题
4.1 主键是多个字段的联合主键,这点在一些数据库产品中,不是一个好的选择项,尤其在MYSQL中,以B+TREE 为核心的MYSQL,这里在数据插入的情况下必须考虑多个列之间的关系,导致数据库DML 操作时的性能降低问题。
4.2 在MYSQL中表的主键是控制表存储中的值的物理存放顺序,在这样的基础上多列的值的存储中会导致在计算行插入顺序时耗费更多的数据库性能。
4.3 多列的设计在业务中会由于一些业务的变化导致主键列在新的业务中不能继续表达唯一性,导致重新建立主键的情况。
5 在数据库中经常使用 count的方式来完成业务功能
在一些程序员的进行业务功能实现中,经常会使用SELECT COUNT(*) 来完成相关的需求中,对于数据是否存在,以及行数的判断等问题,这样早做是十分低效的操作,建议
1 使用 如 类似 if exists (select 1 from table1 limit 1) 的方式来判断表中是否存在数据,而不是用select count(*) 的方式来判断
2 如果要获取表中的行数可以在通过系统表来获得表中的行数,或者通过主键的设计来获取行数,如果 last_id ()等方式,因为一般在大表的获取行数中,获得值一般不要求是 极其准确的,尤其在分页的场景中。
3 通过REDIS 作为计数器的方式来完成获取表行的数量的方式来进行
6 触发器的使用
触发器的使用是一个降低程序复杂性的方案,但是滥用触发器是一个非常糟糕的事情,触发器本身生成了一个事务,复杂的触发器可能将多个表的操作灌入,并且由一个表的操作触发多个表的操作,这样就形成了一个大事务,导致事务锁频繁发生,降低数据库的使用的性能,容易产生一些莫名的数据操作的卡顿,并且在出现问题后,不容易进行排查和发现,所以现代的程序开发中,一般在开发规范中都禁用触发器,作为一个基本操作规范。
7 写查询时,经常用排除法和否定法来撰写语句
select count(*) from table where name <> 'John'; 在撰写语句的时候,经常有一种写法是类似上面的写法,虽然SQL语句可以这样写,但从你写这样的语句会有两个推断:
1 你对这个查询的条件的灵活性要求很高,因为你不能正向确定你的数据需要查询的结果是什么,而是你只能确定你不要什么。
2 你确定你用逆向的方式来查询的数据的量级是极少数的吗,或者说你从业务的发展来看,你只能对于你当前业务在这条语句的产生的理解是不确定的。
这样的情况下,数据库引擎也是这样想的,因为在数据处理中对于否定的方式的查询,数据库也是对于可以获取多少数据是一个未知数的状态,对于一个未知数的情况,不少数据库都是采用 scan all 的方式来解决问题,所以DB 对于反向思维查询的方式一直是不鼓励和不支持的意见。
在这些问题上,解决的方案有很多,上面一部分在提出问题时给了一些建议,一些没有给出建议的部分中有一部分实际上很容易找到解决方案,还有一部分的解决方案不是单纯数据库的层面可以直接解决的,需要revole更多的部分如 业务方面的人员,表设计的人员,开发者等共同构建解决方案。
本文分享自 AustinDatabases 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!