现代网站,性能的瓶颈都围绕着数据库的性能来谈。数据库是存储的核心部件,在日益增长的流量中会凸显数据库的性能瓶颈。从《淘宝技术十年》书中来看,淘宝发展历程中从MYSQL换成了ORACLE又换成了MYSQL集群,每次变换数据库都是因为业务的增长,使得数据库的读写效率达到了瓶颈。作为互联网公司最受欢迎的数据库MYSQL,它有自己独特的魅力:轻便、社区版免费、可做集群等,即便是它拥有这么多特性和优势,我们开发人员也只是觉得它的优势只有:便于使用与学习。

  如果不是身为架构师的开发人员,最经常写到的就是SQL了,一条好的SQL抵得过几百行优化代码。因为程序的各处都在执行SQL,数据库如果执行太多的复杂的SQL,则它可能会卡死,这就意味着你的系统会死掉,有可能丢失大量用户的现在操作,这是灾难性的:别人觉得你的软件不好,丢失了客户。所以,掌握高效SQL的技巧是开发人员的必修课。(虽然我觉得我每天都在写SQL,但是其实在写EXCEL)

  持久层存储大概有内存和硬盘两种(我自己分的),内存级存储严格来说不算持久化存储,它们大体上使用的是NOSQL,存储的格式是BigTable,key,value型存储,存储的数据为非关系型的,现有的产品是Memcached,Redis,MongoDB。推测是使用哈希表数据结构。而硬盘级别的我认为属于严格的持久化存储了,它们使用结构化查询语言SQL,存储的数据为关系型的,现有的产品为MYSQL,ORACLE,DB2等等。

  总之,业务程序员(没有贬低,233)写业务的时候,基本上一个需求就是一个数据查询任务,写出慢的SQL,自然有让它变快的能力。唯一的原则就是:不要让数据库做多余的事情

  • CRUD,日常操作

  作为一个excel工作者(呸),当然是开发出可以供用户使用的excel页面啦。举个栗子,比如用户管理里面的,按不同的条件来查询用户,以及和另一张表共同过滤某些用户数据等。当你的系统做大了,你需要分析用户的行为以促进你的网站业务的增长,比如某种特性的用户(比如购买某种VIP)增长得很快,那么你需要去查询他们最多购买的产品、感兴趣的产品、以及消费区间等等。这其实都是查询语句的应用场景,而且在互联网企业中,查的操作是十分频繁的。

  对于SQL的语句来一个范式,那大概是:insert/delete/select/update 字段操作 from 表 where 筛选条件。虽然字段操作部分各有区别,但是重点在于where子句的编写,因为它的编写决定你SQL的执行时间。

  insert

insert into 表名(字段) values(字段值)

  写操作的执行应该是不算频繁的,对于大多数CRM或者ERP来说,这条语句已经足够了。如果插入多条,那就执行多次吧。

  delete

delete from 表名 where 条件

  删除操作是一种微妙复杂的操作,它不会影响系统性能,但是多表关联的时候,删除需要格外小心,程序中有可能根据某表的某些字段去查这个表的某列数据,你删除掉了,就可能报空异常。所以在设计表和程序的时候,需要考虑一种弱耦合的策略。

  update

update 表名 set 字段1=值1,字段2=值2... where 筛选条件

  更新操作也是一种微妙复杂的操作,系统性能的影响是有可能的,如果高并发写操作,由于博主缺少经验,不是很能想象这种场景处理方式(12306好像就是高读写)。更新的关键是,关联数据字段id不能随意更改,类似于指针丢失的概念。

  select

select 字段名 from 表名 where 筛选条件

  查操作十分的花式,你的产品经理会让你各种方式去筛选数据,因为互联网公司比较在意的是某些条件的数据的价值。再举个栗子,我们需要知道哪些用户是付费的、哪些用户是免费的、那些用户是忠实的、那些用户是活跃的等等,这些条件导致where字句变化多端。在系统有十分多查操作的时候,你的数据量很大,select语句有可能就会卡死数据库。所以,在写select的时候,把需要的字段拿出来就好了,避免写select *,如果你经常select *,那我不知道你会不会被主管打死。(其实我设想,数据库在筛选数据的时候应该是根据where筛选,耗时的是where的计算,而select * 大概是消耗传输带宽,不知道设想得对不对)。提高查询效率大概就只有合理应用索引这个方法了。如果数据量再大,就分库分表什么的了。

  • 源数据的处理

  假设查询一张表,到前台时候需要把数据包装一下,在不需要二次查询的时候,不想让前台看到字段名为key的json数据,那么有可能需要遍历后重新put进Map中,这样就有些无谓操作了。

  1.as能帮到你

   如果你的表是,什么USERNAME,PASSWORD这样全大写的字段,那你在select的时候可以as 别名。

select USERNAME as username,PASSWORD as password,EMAIL as email from USER;

  如果不写as,后面跟着另一个字符串的话默认也会变成别名。别名的作用在联合查询中也很有用处。

select a.字段1 as 字段1别名,b.字段2 as 字段2别名 from 表A as a ,表B as b where 筛选条件

  联合查询中用别名来区分一个SQL中的字段是属于哪个表中的。

  2.活用常用数据库函数

  有些表需要记录最后操作时间,如果在服务器语言中执行插入时候获取当前时间,是不是感觉有些别扭。可以使用now()函数。数据库会将当前数据库时间作为datetime类型写入。

  像某些计算查到内存里计算显得有些别扭,所以记得使用sum()求和和avg()求平均值。(是不是真的像做excel一样)

  count()这个函数是十分常用了,计算总共多少条数据。

  max()min()也十分实用。

  Date_Format()日期转换,少了我在内存中转换的一步,拿来直接用,不过要记得这个返回的会是字符串类型,如果你要使用Date类型,那得在服务器中转换。

  cast(表达式 as decimal)算是很实用的取整函数了,有了它可以少一步在内存中转换。

  所以写一条SQL可以长得很恶心,为了从源数据中拿到马上能用的数据。

select sum(字段1) as 字段1别名,cast(avg(字段2) as decimal) as 字段2别名,Date_Format(字段3,"%Y-%m-%d") as 字段3别名 from 表名 where 筛选条件

  但是从程序上来说,拿到的数据会很爽。

  3.多条数据处理

  博主一度陷入多条数据不会处理的境地,比如一张订单表,需要你分页查询(按用户,按日期,都可以),这回需要什么鬼实现方式?刚开始我想的是查到内存里然后进行计算,某些数据被剔除掉,这会造成你limit语句是个假分页……也就是查出10条,过滤掉了一些,页面上每页显示都不到10条,并且参差不齐。

  这时候我想起大学时候某位前辈说的,一行SQL胜过千万行程序。使用group by就好了。

select sum(订单金额) ,用户编号  from 订单表 where 条件 group by 用户编号 limit n,m

  这样就是聚合翻页了,按照用户编号分组的。

  如果你要筛选订单金额大于某个值的数据呢?头疼,又去内存里遍历?使用having

select sum(订单金额) as 订单金额别名,用户编号  from 订单表 where 条件 group by 用户编号 having 订单金额别名 > a and 订单金额别名 < b limit n,m

  4.升序、降序

  小儿科,order by 某字段 (desc)。这个主要还有一个,比如我想计算用户的购买记录,需要带上时间的。

select sum(购买总额),时间 from 订单表 where 条件 order by 字段 desc(降序 不填为升序)

  这样你出来的时间,会是最早那条。(反正不准)

  为了保证统计的总数的时候,同时拿到最新的那条购买时间,这么写就好了。

select sum(购买总额),max(时间) from 订单表 where 条件 order by 字段
  • 联合查询

  用得很少,因为现在的架构比较提倡单表弱耦合查询,因为联合查询的SQL很难读,并且一次join就要多算一个表,大概是连乘的复杂度。

  A left join B,左联合,表示以左表为基准,无论B有没有数据,A都会按照where条件查询完毕。结果相当于B集合除去A与B的交集。(图我就不画了)

  A right join B,右联合,表示以右表为基准。集合里相当是A除去A与B的交集。

  A inner join ,交集。

  join都可以后面加个on表示集合运算的条件。

   举个例子

select a.字段1,b.字段2 from 表A as a inner/left/right join 表B as b on(a.id=b.id)

  就是以a为中心,连接b表查询。

  在联合查询中,一般会以某表为中心表,散发式连接多表进行信息筛选。

  模拟一个业务环节,有一张用户表,用户会员信息表,用户订单表。可以查什么数据呢?这就很复杂了,比如查询还在会员期内的会员购买订单的金额、非会员的购买金额、未付款的订单金额等等。CRM系统的需求十分的变化多端,为的就是分析用户的行为从而增加软件的收入。

CREATE TABLE `USER` (
`GMT_CREATE` datetime NOT NULL,
`GMT_MODIFIED` datetime NOT NULL,
`USER_ID` varchar(64) CHARACTER SET latin1 NOT NULL,
`USER_NAME` varchar(64) CHARACTER SET latin1 DEFAULT NULL,
`USER_PASSWORD` varchar(64) CHARACTER SET latin1 DEFAULT NULL,
`USER_EMAIL` varchar(64) CHARACTER SET latin1 DEFAULT NULL,
PRIMARY KEY (`USER_ID`),
UNIQUE KEY `USER_ID_UNIQUE` (`USER_ID`),
KEY `USER_ID` (`USER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `USER_MEMBER` (
`GMT_CREATE` datetime DEFAULT NULL,
`USER_ID` varchar(64) NOT NULL COMMENT '会员id',
`MEMBER_START` datetime NOT NULL COMMENT '会员开始时间',
`MEMBER_END` datetime NOT NULL COMMENT '会员结束时间',
`MEMBER_RANK` varchar(16) DEFAULT NULL COMMENT '会员等级',
PRIMARY KEY (`USER_ID`),
UNIQUE KEY `USER_ID_UNIQUE` (`USER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员信息';
CREATE TABLE `USER_ORDER` (
`GMT_CREATE` datetime DEFAULT NULL,
`ID` int(20) NOT NULL AUTO_INCREMENT,
`USER_ID` varchar(64) DEFAULT NULL COMMENT '用户id',
`ORDER_PRICE` varchar(45) DEFAULT NULL COMMENT '订单金额',
`STATUS` varchar(45) DEFAULT NULL COMMENT '订单支付状态',
PRIMARY KEY (`ID`),
KEY `uid` (`USER_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='用户订单';

  

  添加了一些数据。

  举个例子,我想查在期内的用户消费量,说着简单,写着就复杂了。

select a.USER_ID ,a.USER_NAME ,sum(c.ORDER_PRICE) from USER as a inner join USER_MEMBER as b on(a.USER_ID = b.USER_ID and MEMBER_END > now()) inner join USER_ORDER as c on(a.USER_ID = c.USER_ID and c.STATUS = 'yes') group by a.USER_ID

  

  • 结语

    经过实际开发的洗礼,深深的认识到写SQL的重要性,高效的SQL使得程序也变得简洁,对于SQL结果集的数据处理也是要小心的,一不注意就会报空指针异常。作为一名走向资深EXCEL开发的工程师来说(呸),确实,SQL是基础中的基础,在此做一个阶段性的总结。

结合业务,精炼SQL的更多相关文章

  1. [Skill]从零掌握80%的业务查询SQL语句

    前言 本篇文章的主要目的是帮助初学者快速入门SQL查询,从而解决实际业务中80%的SQL查询问题. 本文主要框架如下: 上篇:介绍SQL的语法顺序和执行顺序 中篇:介绍条件子句.分组查询和排序的细节 ...

  2. SQL Server最近怎样了

    SQL Server最近怎样了 又到年终了,大家都作最后冲刺 最近园子里真的多了很多口水帖,无论大家争论得多么激烈,时间依然滴答滴答地过,争论完之后我们依然要继续埋头苦干 为年终奖.为明年做准备 这里 ...

  3. SQL SERVER作业的Schedules浅析

    SQL SERVER作业的计划(Schedules),如果你没仔细研究过或没有应用一些复杂的计划(Schedules),那么你觉得SQL SERVER作业的计划(Schedules)非常好用,也没啥问 ...

  4. Hibernated的sql查询

    记录一下学习Hibernate的心得 1.为什么HIbernate会支持原生态的sql查询? HQL查询语句虽然方便我们查询,但是基于HQL的查询会将查询出来的对象保存到hibernate的缓存当中, ...

  5. 数据库 基于索引的SQL语句优化之降龙十八掌(转)

    一篇挺不错的关于SQL语句优化的文章,因不知原始出处,故未作引用说明! 1 前言      客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不够优化,导致数据库性能急 ...

  6. 初次使用SQL调优建议工具--SQL Tuning Advisor

    在10g中,Oracle推出了自己的SQL优化辅助工具: SQL优化器(SQL Tuning Advisor :STA),它是新的DBMS_SQLTUNE包. 使用STA一定要保证优化器是CBO模式下 ...

  7. oracle sql 优化大全

    转自: http://panshaobinsb.iteye.com/blog/1718233 http://yulimeander.blog.sohu.com/115850824.html 最近遇到了 ...

  8. 关于索引的sql语句优化之降龙十八掌

    1 前言       客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不够优化,导致数据库性能急剧下降,小型机idle所剩无几,应用服务器断连.超时,严重影响业务的正 ...

  9. sqlt 之 分析 DB upgrade 导致SQL 性能下降 的方法 xplore

    https://blog.csdn.net/lukeUnique/article/details/79331779 https://mauro-pagano.com/2014/10/27/when-t ...

随机推荐

  1. Kubernetes的UI界面Kubernetes Dashboard的搭建

    1.搭建准备 Kubernetes集群的安装部署 2.搭建过程 2.1.在master节点上创建kubernetes-dashboard.yaml cd /etc/kubernetes vim kub ...

  2. CHEMISTS DISCOVER A SAFE, GREEN METHOD TO PROCESS RED PHOSPHORUS

                   When it comes to making phosphorus compounds, chemists have traditionally relied on w ...

  3. RNA -seq

    RNA -seq RNA-seq目的.用处::可以帮助我们了解,各种比较条件下,所有基因的表达情况的差异. 比如:正常组织和肿瘤组织的之间的差异:检测药物治疗前后,基因表达的差异:检测发育过程中,不同 ...

  4. Android实现求和运算

    实验要求: 用Android实现一个界面,在该页面点击实现加法运算. 代码实现 实现结果 输入结果为空时,如图 问题及解决 函数中使用了强制转换,当输入字符串是也能转换为int型数据,但是当输入字符时 ...

  5. JVM GC 机制与性能优化

    目录(?)[+] 1 背景介绍 与C/C++相比,JAVA并不要求我们去人为编写代码进行内存回收和垃圾清理.JAVA提供了垃圾回收器(garbage collector)来自动检测对象的作用域),可自 ...

  6. ASP.NET Core2集成Office Online Server(OWAS)实现办公文档的在线预览与编辑(支持word\excel\ppt\pdf等格式)

    Office Online Server是微软开发的一套基于Office实现在线文档预览编辑的技术框架(支持当前主流的浏览器,且浏览器上无需安装任何插件,支持word.excel.ppt.pdf等文档 ...

  7. 教你如何学python

    首先,你要有自信心,要明确学习目的.学Python,可以解决在软件使用中所遇到的问题,可以为找到理想工作添加重要砝码.还能锻炼思维,使我们的逻辑思维更加严密:能不断享受到创新的乐趣,将走在高科技的前沿 ...

  8. visual studio code中使用emmet插件在.vue文件失效

    使用visual studio code编辑.vue文件时,emmet插件无法使用,可以通过以下两种试解决: 1.文件→设置,在右侧窗口添加以下代码: "emmet.syntaxProfil ...

  9. [Erlang28]使用匿名函数灵活组合不同的case

    cowboy_http.erl里面的date1/2 启示: 以前一般写case里都是这样子: date1(Date) -> case month1(Date) of {error,badarg} ...

  10. 执行计划--在存储过程中使用SET对执行计划的影响

    --如果在存储过程中定义变量,并为变量SET赋值,该变量的值无法为执行计划提供参考(即执行计划不考虑该变量),将会出现预估行数和实际行数相差过大导致执行计划不优的情况--如果在存储过程中使用SET为存 ...