作为前端开发人员来说,大部分人都没有深入的接触过数据库操作,更何况是优化数据库查询的操作了。
但作为2020年往后的前端,serverless 已经可以为大量业务服务的当下,操作并了解数据库也是必要的。欣仔觉得,前端只是当前某个服务的领域,任何一名身处在这个领域的开发人员都不应该以“前端开发工程师”自居,而应该是“软件开发工程师”为方向不断武装羽翼才行。
简而言之:“前后端通吃”,可以切图玩像素,以可以sql撸数据,这样你才会变得受欢迎。
当然本文讲述的不是数据库的基础,啥第一范式第二范式也不是这里要说到的内容,我来讲讲数据库索引。
曾经有名运维人员,通过跳板机登陆了他们家公司的数据库,把所有数据都清空,导致全网的人都做了吃瓜群众。这种毁灭性的操作让用户瞬间感觉到异常。。
曾经的曾经有个还有技术总监,因为对公司不满,默默地删除了公司重要数据库数据库索引,然后他们家的系统就慢慢的慢慢的不正常了。
前一种操作就像杀人砍头,非常直接。后一种操作就是种蛊下毒,虽不至于立即断送系统的生命,但久而久之,系统慢慢失去了神志,新的数据进不来,旧的数据也出不去,跟死了也没啥区别。
那数据库索引到底是啥?
且看我用js的方式慢慢道来:
假设我现在有100000条事先准备好的随机数,常规的存储就是一个100000长度的数组data,大概长这样。
{ id: 0, content: 10116170.397752885 }, { id: 1, content: 9690201.810982745 }, { id: 2, content: 5731487.435941743 }, { id: 3, content: 11888385.207056893 }, { id: 4, content: 11932241.467477538 }, { id: 5, content: 2078797.6020045406 }, { id: 6, content: 6265169.710994962 }, { id: 7, content: 11201556.057179725 }, .......
当我要去查询id 为 100的内容的时候,我们最常规的查询方式就是循环,我们会写一个这样的函数:
function selectContent(data,key,value){ for(let i =0;i<data.length;i++){ if(data[i][key] === value){ return data[i] } } return null;}
这看起来没什么问题。在搜索id 为100 的值的时候,这样去执行:
let result = selectContent(data,"id",100);
得到一个如下的返回结果:
{ id: 100, content: 12727639.986723457 }
按照这样的查询方式,我连续执行了100次随机id的搜索,最终平均花费10毫秒。由于本身数据结构简单,所以不会花费太多的时间。存在一个缺点,如果id 不存在,当前这个数组还是会执行100000次的循环遍历,这在一定程度上会造成资源的大量浪费,特别是当数组长度越来越长的时候。
我们可以通过加索引的方式比较下时间。
首先看下索引的定义:(摘自百度百科)
索引是对 数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。
写似懂非懂。总之,创建索引可以帮你额外创建一个数据结构,这个数据结构额外构建起了key 和值的关系,让你免去上面说到的循环遍历查询,这样说起来就很简单易懂了。
就是用一个Object 去托管这批数据。
回到上面说的10万条数据,我们为其创建索引,索引的key 为id。
新建一个Object对象,在查询操作之前遍历数组,Object 的每个key 就是数组内每行数据的id值。
function buildIndex(data,key){ let re ={}; for(var i in data){ re[data[i][key]]= data[i]; } return re;}
let dataIndexForId = buildIndex(data,"id")
而后,我们用dataIndexForId为数据基础查询,先写个查询函数:
function selectContentByIndex(data,key){ return data[key]}
按照这样的查询方式,我连续执行了100次随机id的搜索,最终平均花费0毫秒,而且还非常好的解决了id值不存在的情况下造成资源浪费的问题产生。
我们把查询次数放大到1000条。
非索引方式的查询在我的机器上耗时 20毫秒左右,而索引方式依旧是 0-1ms。
可想而知,如果一个正在线上稳定运行的系统,当我们神不知鬼不觉删除了了数据库的索引,数据库查询直接就龟速起航了。
其实是一个很简单的原理,不过在实际的数据库的处理过程中,肯定比我所述的要复杂的多,实际涉及到的查询的维度好多很多,但其最终原理都是抛弃循环遍历,创造额外的数据结构做存储。这会对内存造成一定的提升,但是控制好存储的内容,影响甚至可以说是微乎其微的。但至少大家知道如何通过这种方式提高查询效率,这种方式在前端的很多应用场景下都会用到。
比如 vue 框架 和react 框架中的根据数组生成列表,框架内都会建议在列表的单项中添加key属性一样。
VUE:<li v-for="(item,i) in list" :key="i">{{item}}</li>
REACT:list.map((item,i)=>{ <li key={i}>{item}</li>})
其作用也是为了在渲染过程中利用key去获取虚拟dom的内容,而不用在渲染过程中反复去循环遍历数组。
以上便是简单的科普文啦。。很久不更新公众号了,想着再不写点什么大概会要被腾讯遗弃了,最后致敬每一位在一线与冠状病毒斗争的医护人员,你们都是英雄。同时也致敬每一位响应国家号召不出去添乱的普通百姓,你们也都是英雄~2020虽然开年不济,每一个人也都对未来满怀期待,这才是这段时间我们蛰伏在各自的小角落里的最大的动力啦,2020加油~