• 关于

    查询数据库某一字段的值

    的搜索结果

问题

写一个关于json串的sql查询

我想写一个关于json串的sql查询,比如说我数据库的某一字段是'BZ',内容是{name:123,age: 14},{name:456,age: 15}这样的,请问如何写查询,比如说通过name的值来查找 age的值,我要比如说我要查的n...
吴孟桥 2019-12-01 20:00:54 978 浏览量 回答数 1

问题

我想写一个关于json串的sql查询,具体请看下面

我想写一个关于json串的sql查询,比如说我数据库的某一字段是'BZ',内容是{name:123,age: 14},{name:456,age: 15}这样的,请问如何写查询,比如说通过name的值来查找 age的值,我要比如说我要查的n...
杨冬芳 2019-12-01 20:18:57 836 浏览量 回答数 1

问题

一个sql解析json字符串的问题

我想在IDE写一个关于json串的sql查询,比如说我数据库的某一字段是'MT',内容是{"name":"123","age":"12"}(只有这一串json),应该怎么解析这个json把key设成字段名,字段下面是value值,求sql,...
sunshine_ran 2019-12-01 20:24:59 1899 浏览量 回答数 1

Quick BI 数据可视化分析平台

2020年入选全球Gartner ABI魔力象限,为中国首个且唯一入选BI产品

问题

如何选择拆分键

拆分键即分库/分表字段,是在水平拆分过程中用于生成拆分规则的数据表字段。DRDS 根据拆分键的值将数据表水平拆分到每个 RDS 实例上的物理分库中。 数据表拆分的首要原则,就是要尽可能找到数据表中的数据在业务逻...
猫饭先生 2019-12-01 21:20:53 1364 浏览量 回答数 0

问题

从2000万条开房数据优化谈检索:报错

看到以前一个帖子 2000万条开房数据,如何快速查询(数据库优化)。(按照规矩,先把福利贴上 http://kfxx.info)  一、引言 对...
kun坤 2020-06-08 11:03:28 21 浏览量 回答数 1

回答

1. 原始单据与实体之间的关系 可以是一对一、一对多、多对多的关系。在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体。在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个实体,或多张原始单证对应一个实体。 这里的实体可以理解为基本表。明确这种对应关系后,对我们设计录入界面大有好处。 〖例1〗:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表、社会关系表、工作简历表。这就是“一张原始单证对应多个实体”的典型例子。 2. 主键与外键 一般而言,一个实体不能既无主键又无外键。在E—R 图中, 处于叶子部位的实体, 可以定义主键,也可以不定义主键(因为它无子孙), 但必须要有外键(因为它有父亲)。 主键与外键的设计,在全局数据库的设计中,占有重要地位。当全局数据库的设计完成以后,有个美国数据库设计专家说:“键,到处都是键,除了键之外,什么也没有”,这就是他的数据库设计经验之谈,也反映了他对信息系统核心(数据模型)的高度抽象思想。 因为:主键是实体的高度抽象,主键与外键的配对,表示实体之间的连接。 3. 基本表的性质 基本表与中间表、临时表不同,因为它具有如下四个特性: 原子性。基本表中的字段是不可再分解的。原始性。基本表中的记录是原始数据(基础数据)的记录。演绎性。由基本表与代码表中的数据,可以派生出所有的输出数据。稳定性。基本表的结构是相对稳定的,表中的记录是要长期保存的。理解基本表的性质后,在设计数据库时,就能将基本表与中间表、临时表区分开来。 4. 范式标准 基本表及其字段之间的关系, 应尽量满足第三范式。但是,满足第三范式的数据库设计,往往不是最好的设计。为了提高数据库的运行效率,常常需要降低范式标准:适当增加冗余,达到以空间换时间的目的。〖例2〗:有一张存放商品的基本表,如表1所示。“金额”这个字段的存在,表明该表的设计不满足第三范式,因为“金额”可以由“单价”乘以“数量”得到,说明“金额”是冗余字段。但是,增加“金额”这个冗余字段,可以提高查询统计的速度,这就是以空间换时间的作法。在Rose 2002中,规定列有两种类型:数据列和计算列。“金额”这样的列被称为“计算列”,而“单价”和“数量”这样的列被称为“数据列”。640?wx_fmt=png 表1 商品表的表结构 5. 通俗地理解三个范式 通俗地理解三个范式,对于数据库设计大有好处。在数据库设计中,为了更好地应用三个范式,就必须通俗地理解三个范式(通俗地理解是够用的理解,并不是最科学最准确的理解): 第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解 第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性; 第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。 没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。 6. 要善于识别与正确处理多对多的关系 若两个实体之间存在多对多的关系,则应消除这种关系。消除的办法是,在两者之间增加第三个实体。这样,原来一个多对多的关系,现在变为两个一对多的关系。要将原来两个实体的属性合理地分配到三个实体中去。 这里的第三个实体,实质上是一个较复杂的关系,它对应一张基本表。一般来讲,数据库设计工具不能识别多对多的关系,但能处理多对多的关系。 〖例3〗:在“图书馆信息系统”中,“图书”是一个实体,“读者”也是一个实体。这两个实体之间的关系,是一个典型的多对多关系:一本图书在不同时间可以被多个读者借阅,一个读者又可以借多本图书。为此,要在二者之间增加第三个实体,该实体取名为“借还书”,它的属性为:借还时间、借还标志(0表示借书,1表示还书),另外,它还应该有两个外键(“图书”的主键,“读者”的主键),使它能与“图书”和“读者”连接。 7. 主键PK的取值方法 PK是供程序员使用的表间连接工具,可以是一无物理意义的数字串, 由程序自动加1来实现。也可以是有物理意义的字段名或字段名的组合。不过前者比后者好。当PK是字段名的组合时,建议字段的个数不要太多,多了不但索引占用空间大,而且速度也慢。 8. 正确认识数据冗余 主键与外键在多表中的重复出现, 不属于数据冗余,这个概念必须清楚,事实上有许多人还不清楚。非键字段的重复出现, 才是数据冗余!而且是一种低级冗余,即重复性的冗余。高级冗余不是字段的重复出现,而是字段的派生出现。〖例4〗:商品中的“单价、数量、金额”三个字段,“金额”就是由“单价”乘以“数量”派生出来的,它就是冗余,而且是一种高级冗余。冗余的目的是为了提高处理速度。 只有低级冗余才会增加数据的不一致性,因为同一数据,可能从不同时间、地点、角色上多次录入。因此,我们提倡高级冗余(派生性冗余),反对低级冗余(重复性冗余)。 9. E--R图没有标准答案 信息系统的E--R图没有标准答案,因为它的设计与画法不是惟一的,只要它覆盖了系统需求的业务范围和功能内容,就是可行的。反之要修改E--R图。尽管它没有惟一的标准答案,并不意味着可以随意设计。好的E—R图的标准是:结构清晰、关联简洁、实体个数适中、属性分配合理、没有低级冗余。 10. 视图技术在数据库设计中很有用 与基本表、代码表、中间表不同,视图是一种虚表,它依赖数据源的实表而存在。视图是供程序员使用数据库的一个窗口,是基表数据综合的一种形式, 是数据处理的一种方法,是用户数据保密的一种手段。 为了进行复杂处理、提高运算速度和节省存储空间, 视图的定义深度一般不得超过三层。若三层视图仍不够用, 则应在视图上定义临时表, 在临时表上再定义视图。这样反复交迭定义, 视图的深度就不受限制了。 对于某些与国家政治、经济、技术、军事和安全利益有关的信息系统,视图的作用更加重要。这些系统的基本表完成物理设计之后,立即在基本表上建立第一层视图,这层视图的个数和结构,与基本表的个数和结构是完全相同。并且规定,所有的程序员,一律只准在视图上操作。 只有数据库管理员,带着多个人员共同掌握的“安全钥匙”,才能直接在基本表上操作。请读者想想:这是为什么? 11. 中间表、报表和临时表 中间表是存放统计数据的表,它是为数据仓库、输出报表或查询结果而设计的,有时它没有主键与外键(数据仓库除外)。临时表是程序员个人设计的,存放临时记录,为个人所用。基表和中间表由DBA维护,临时表由程序员自己用程序自动维护。 12. 完整性约束表现在三个方面 域的完整性:用Check来实现约束,在数据库设计工具中,对字段的取值范围进行定义时,有一个Check按钮,通过它定义字段的值城。 参照完整性:用PK、FK、表级触发器来实现。用户定义完整性:它是一些业务规则,用存储过程和触发器来实现。 13. 防止数据库设计打补丁的方法是“三少原则” 1、一个数据库中表的个数越少越好。只有表的个数少了,才能说明系统的E--R图少而精,去掉了重复的多余的实体,形成了对客观世界的高度抽象,进行了系统的数据集成,防止了打补丁式的设计; 2、一个表中组合主键的字段个数越少越好。因为主键的作用,一是建主键索引,二是做为子表的外键,所以组合主键的字段个数少了,不仅节省了运行时间,而且节省了索引存储空间; 3、一个表中的字段个数越少越好。只有字段的个数少了,才能说明在系统中不存在数据重复,且很少有数据冗余,更重要的是督促读者学会“列变行”,这样就防止了将子表中的字段拉入到主表中去,在主表中留下许多空余的字段。所谓“列变行”,就是将主表中的一部分内容拉出去,另外单独建一个子表。这个方法很简单,有的人就是不习惯、不采纳、不执行。 数据库设计的实用原则是:在数据冗余和处理速度之间找到合适的平衡点。“三少”是一个整体概念,综合观点,不能孤立某一个原则。该原则是相对的,不是绝对的。“三多”原则肯定是错误的。试想:若覆盖系统同样的功能,一百个实体(共一千个属性) 的E--R图,肯定比二百个实体(共二千个属性)的E--R图,要好得多。 提倡“三少”原则,是叫读者学会利用数据库设计技术进行系统的数据集成。数据集成的步骤是将文件系统集成为应用数据库,将应用数据库集成为主题数据库,将主题数据库集成为全局综合数据库。 集成的程度越高,数据共享性就越强,信息孤岛现象就越少,整个企业信息系统的全局E—R图中实体的个数、主键的个数、属性的个数就会越少。提倡“三少”原则的目的,是防止读者利用打补丁技术,不断地对数据库进行增删改,使企业数据库变成了随意设计数据库表的“垃圾堆”,或数据库表的“大杂院”,最后造成数据库中的基本表、代码表、中间表、临时表杂乱无章,不计其数,导致企事业单位的信息系统无法维护而瘫痪。 “三多”原则任何人都可以做到,该原则是“打补丁方法”设计数据库的歪理学说。“三少”原则是少而精的原则,它要求有较高的数据库设计技巧与艺术,不是任何人都能做到的,因为该原则是杜绝用“打补丁方法”设计数据库的理论依据。 14. 提高数据库运行效率的办法 在给定的系统硬件和系统软件条件下,提高数据库系统的运行效率的办法是:在数据库物理设计时,降低范式,增加冗余, 少用触发器, 多用存储过程。 当计算非常复杂、而且记录条数非常巨大时(例如一千万条),复杂计算要先在数据库外面,以文件系统方式用C++语言计算处理完成之后,最后才入库追加到表中去。这是电信计费系统设计的经验。 发现某个表的记录太多,例如超过一千万条,则要对该表进行水平分割。水平分割的做法是,以该表主键PK的某个值为界线,将该表的记录水平分割为两个表。若发现某个表的字段太多,例如超过八十个,则垂直分割该表,将原来的一个表分解为两个表。 对数据库管理系统DBMS进行系统优化,即优化各种系统参数,如缓冲区个数。在使用面向数据的SQL语言进行程序设计时,尽量采取优化算法。 总之,要提高数据库的运行效率,必须从数据库系统级优化、数据库设计级优化、程序实现级优化,这三个层次上同时下功夫。
茶什i 2019-12-27 15:54:46 0 浏览量 回答数 0

回答

换成多个查询条件是对的,如果一定要连接查询的话,要注意 || 只要其中一个字段为null结果为null,所以每个字段要给他一个默认值: SELECT * FROM [表名] WHERE ifnull(name,'') || ifnull(phone,'') || ifnull(adress,'') || ifnull(qq,'') LIKE '%某值%' ######棒,用函数,学习了######nvl?######ifnull等同于nvl 新学数据库不懂知识勿见怪###### nvl 是函数 不是SQL 语句 ######如果WHERE 字段每个都有索引,建议分开查,然后数据合并######回复 @菲菲OSC : 通过SQL可以合并,程序也可以。######怎么分开查然后数据合并呢? sql 语句怎么写?######@  行者GC 怎么分开查 然后数据合并呢?######用 or######+10086######or 我也想过,只是觉得语句长了点。。。###### 数据量大得话,应该用全文检索了, 毕竟  %% 用不到索引,效率很低。 数据量一般的话, 可以考虑 or,union。concat_ws 可能会有 误查得情况 ######谢###### 过滤后有2中类型数据 1. 姓名和地址 不是全数字 2. QQ和手机是全数字 然后针对查询就好 ###### 引用来自“烧土豆”的答案 过滤后有2中类型数据 1. 姓名和地址 不是全数字 2. QQ和手机是全数字 然后针对查询就好 不是很明白,新手,sql语句不是很熟,写一下怎么实现好吗 ######回复 @烧土豆 : 谢谢指教######一个输入框是四种类型关键词的入口 如果or查询肯定很慢 所以给出思路就是劲量分拆这四种类型的关键词 回复中我简单的分拆成2中类型的 一个全数字 一个不全数字 你可以再细分 当然能分成一种最好 原则是不要把压力给数据库
kun坤 2020-06-09 22:32:23 0 浏览量 回答数 0

问题

业务逻辑写在数据库还是自身应用程序?

SQL应该负责怎么样的CURD,分组、排序、可能根据业务逻辑只是选择性查个别字段、使用SQL函数等等让不让数据库做?还是自己用编程语言(比如java、c++)写的应用程序里处理数据?实例:统计2015-03-22 ~ 2015-03-24期...
蛮大人123 2019-12-01 20:02:37 1552 浏览量 回答数 1

问题

如何查询日志中的语法?

为了能够帮助您更有效地查询日志,Log Service 提供一套查询语法用以表达查询条件。您可以通过 Log Service API 中的 GetLogs 和 GetHistograms 接口或者在 Log Service ...
轩墨 2019-12-01 21:57:34 1619 浏览量 回答数 0

问题

Android数据库框架-Archiver(LiteOrm)的使用?报错

           在Android开发中,大家开发不同项目,不同的项目就不有不同需求。但是不管是什么项目都会涉及到数据存储。比如SharePreferences,SQLite,Fi...
爱吃鱼的程序员 2020-06-12 14:43:40 2 浏览量 回答数 1

回答

get和load,一个是直接加载,并不是直接去数据库查询,如果缓存里有,首先到缓存里找,缓存分为一级缓存和二级缓存,首先到一级缓存中查找;如果在session关闭之后进行获取类的名字之类的属性,依然会获取到,例:Order od = (Order) session.get(Order.class, 1);通过get获取的Order类是一个持久化类,如果session关闭之后进行获取,od.getName,它就会变成托管状态,但是这个对象还是有的,所以没事;另一个是懒加载,他不会直接进行操作,就是除了获取id(标识符)和类.class时,获取其他的类属性都会进行操作,例:Account acc=(Account)session.load(Account.class,new Long(1)); //返回一个代理对象System.out.println(acc.getId);System.out.prontln(acc.getLonginName());这里的1是一个代理对象,如果只获取他的id,则不会加载,不会出现select语句,只有获取除他和本身之外才会进行查找;否则访问的只是他的代理对象而已;如果需要取消懒加载,就只需要在你想获取的类属性的映射文件的把他改为false就可以了,这样懒加载就取消了,这里只对load管用,对get()毫无影响;如果把他System.out.prontln(acc.getLonginName());放在session关闭之后,则会出现错误,因为这里只产生了一个代理对象,没有真正去查,把session关之后,他会去查数据库,要发出sql语句,因为发出sql语句需要在session里面,所以session关了之后,就不能使用了;接下来说一说他们之间的区别,延迟加载的过程:通过代理(Proxy)机制来实现延迟加载。Hibernate从数据库获取某一个对象数据时、获取某一个对象的集合属性值时,或获取某一个对象所关联的另一个对象时,由于没有使用该对象的数据(除标识符外),Hibernate并不从数据库加载真正的数据,而只是为该对象创建一个代理对象来代表这个对象,这个对象上的所有属性都为默认值;只有在真正需要使用该对象的数据时才创建这个真正的对象,真正从数据库中加载它的数据。如果只是访问对象标示符属性,就没有必要初始化代码。Account acc=(Account)session.load(Account.class,new Long(1)); //返回一个代理对象 Order order=new Order(); order.setCreateTime(new Date()); order.setAccount(acc); Session.save(order);在这只需要Account实例来创建一个新的Order订单对象,当调用session.save(order)时,也只需要Account的主标示符值作为外键保存到订单表的对应字段中。这样就少执行一条select语句,从而提高查询效率。Hibernate中默认采用延迟加载的情况主要有以下几种:当调用Session上的load()方法加载一个实体时,会采用延迟加载。当Session加载某个实体时,会对这个实体中的集合属性值采用延迟加载。(one-to-many)例:当Client这个类里具有集合属性,Client client = (Client) session.get(Client.class, 4);System.out.println(client.getName());获取他的名字,你会发现只有一条sql语句,因为采用了延迟加载,所以如果想取消,就在该映射文件下里面把lazy改成false;当Session加载某个实体时,会对这个实体所单端关联(one-to-one, many-to-one)的另一个实体对象采用延迟加载。能够懒加载的对象都是被改写过的代理对象,当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getId和getClass除外)hibernate会初始化这些代理,或用Hibernate.initialize(proxy)来初始化代理对象;当相关联的session关闭后,再访问懒加载的对象将出现异常。2、 关闭延迟加载在加载单个实体时,如果不需要延迟加载,就可以使用session的get()方法。当Session加载某个实体时,不需要对这个实体中的集合属性值延迟加载,而是要立即加载。这时可以在映射文件中针对 这个集合属性的配置元素(,,…)添加属性lazy=“false”。当Session加载某个实体时,不需要对这个实体所单端关联的另一个实体对象延迟加载,就可以在映射文件中对这个单端关联的配置元素(, )添加属性lazy=“false”。注意:one-to-one不能有constrained=true如果回答对您有帮助,请采纳
小旋风柴进 2019-12-02 02:11:32 0 浏览量 回答数 0

回答

92题 一般来说,建立INDEX有以下益处:提高查询效率;建立唯一索引以保证数据的唯一性;设计INDEX避免排序。 缺点,INDEX的维护有以下开销:叶节点的‘分裂’消耗;INSERT、DELETE和UPDATE操作在INDEX上的维护开销;有存储要求;其他日常维护的消耗:对恢复的影响,重组的影响。 需要建立索引的情况:为了建立分区数据库的PATITION INDEX必须建立; 为了保证数据约束性需要而建立的INDEX必须建立; 为了提高查询效率,则考虑建立(是否建立要考虑相关性能及维护开销); 考虑在使用UNION,DISTINCT,GROUP BY,ORDER BY等字句的列上加索引。 91题 作用:加快查询速度。原则:(1) 如果某属性或属性组经常出现在查询条件中,考虑为该属性或属性组建立索引;(2) 如果某个属性常作为最大值和最小值等聚集函数的参数,考虑为该属性建立索引;(3) 如果某属性经常出现在连接操作的连接条件中,考虑为该属性或属性组建立索引。 90题 快照Snapshot是一个文件系统在特定时间里的镜像,对于在线实时数据备份非常有用。快照对于拥有不能停止的应用或具有常打开文件的文件系统的备份非常重要。对于只能提供一个非常短的备份时间而言,快照能保证系统的完整性。 89题 游标用于定位结果集的行,通过判断全局变量@@FETCH_STATUS可以判断是否到了最后,通常此变量不等于0表示出错或到了最后。 88题 事前触发器运行于触发事件发生之前,而事后触发器运行于触发事件发生之后。通常事前触发器可以获取事件之前和新的字段值。语句级触发器可以在语句执行前或后执行,而行级触发在触发器所影响的每一行触发一次。 87题 MySQL可以使用多个字段同时建立一个索引,叫做联合索引。在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引。具体原因为:MySQL使用索引时需要索引有序,假设现在建立了"name,age,school"的联合索引,那么索引的排序为: 先按照name排序,如果name相同,则按照age排序,如果age的值也相等,则按照school进行排序。因此在建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询需求频繁或者字段选择性高的列放在前面。此外可以根据特例的查询或者表结构进行单独的调整。 86题 建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合。如果需要建立联合索引的话,还需要考虑联合索引中的顺序。此外也要考虑其他方面,比如防止过多的所有对表造成太大的压力。这些都和实际的表结构以及查询方式有关。 85题 存储过程是一组Transact-SQL语句,在一次编译后可以执行多次。因为不必重新编译Transact-SQL语句,所以执行存储过程可以提高性能。触发器是一种特殊类型的存储过程,不由用户直接调用。创建触发器时会对其进行定义,以便在对特定表或列作特定类型的数据修改时执行。 84题 存储过程是用户定义的一系列SQL语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程,而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。 83题 减少表连接,减少复杂 SQL,拆分成简单SQL。减少排序:非必要不排序,利用索引排序,减少参与排序的记录数。尽量避免 select *。尽量用 join 代替子查询。尽量少使用 or,使用 in 或者 union(union all) 代替。尽量用 union all 代替 union。尽量早的将无用数据过滤:选择更优的索引,先分页再Join…。避免类型转换:索引失效。优先优化高并发的 SQL,而不是执行频率低某些“大”SQL。从全局出发优化,而不是片面调整。尽可能对每一条SQL进行 explain。 82题 如果条件中有or,即使其中有条件带索引也不会使用(要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引)。对于多列索引,不是使用的第一部分,则不会使用索引。like查询是以%开头。如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引。如果mysql估计使用全表扫描要比使用索引快,则不使用索引。例如,使用<>、not in 、not exist,对于这三种情况大多数情况下认为结果集很大,MySQL就有可能不使用索引。 81题 主键不能重复,不能为空,唯一键不能重复,可以为空。建立主键的目的是让外键来引用。一个表最多只有一个主键,但可以有很多唯一键。 80题 空值('')是不占用空间的,判断空字符用=''或者<>''来进行处理。NULL值是未知的,且占用空间,不走索引;判断 NULL 用 IS NULL 或者 is not null ,SQL 语句函数中可以使用 ifnull ()函数来进行处理。无法比较 NULL 和 0;它们是不等价的。无法使用比较运算符来测试 NULL 值,比如 =, <, 或者 <>。NULL 值可以使用 <=> 符号进行比较,该符号与等号作用相似,但对NULL有意义。进行 count ()统计某列的记录数的时候,如果采用的 NULL 值,会被系统自动忽略掉,但是空值是统计到其中。 79题 HEAP表是访问数据速度最快的MySQL表,他使用保存在内存中的散列索引。一旦服务器重启,所有heap表数据丢失。BLOB或TEXT字段是不允许的。只能使用比较运算符=,<,>,=>,= <。HEAP表不支持AUTO_INCREMENT。索引不可为NULL。 78题 如果想输入字符为十六进制数字,可以输入带有单引号的十六进制数字和前缀(X),或者只用(Ox)前缀输入十六进制数字。如果表达式上下文是字符串,则十六进制数字串将自动转换为字符串。 77题 Mysql服务器通过权限表来控制用户对数据库的访问,权限表存放在mysql数据库里,由mysql_install_db脚本初始化。这些权限表分别user,db,table_priv,columns_priv和host。 76题 在缺省模式下,MYSQL是autocommit模式的,所有的数据库更新操作都会即时提交,所以在缺省情况下,mysql是不支持事务的。但是如果你的MYSQL表类型是使用InnoDB Tables 或 BDB tables的话,你的MYSQL就可以使用事务处理,使用SET AUTOCOMMIT=0就可以使MYSQL允许在非autocommit模式,在非autocommit模式下,你必须使用COMMIT来提交你的更改,或者用ROLLBACK来回滚你的更改。 75题 它会停止递增,任何进一步的插入都将产生错误,因为密钥已被使用。 74题 创建索引的时候尽量使用唯一性大的列来创建索引,由于使用b+tree做为索引,以innodb为例,一个树节点的大小由“innodb_page_size”,为了减少树的高度,同时让一个节点能存放更多的值,索引列尽量在整数类型上创建,如果必须使用字符类型,也应该使用长度较少的字符类型。 73题 当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下: 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读。垂直分区: 根据数据库里面数据表的相关性进行拆分。简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。水平分区: 保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。水平拆分可以支撑非常大的数据量。 72题 乐观锁失败后会抛出ObjectOptimisticLockingFailureException,那么我们就针对这块考虑一下重试,自定义一个注解,用于做切面。针对注解进行切面,设置最大重试次数n,然后超过n次后就不再重试。 71题 一致性非锁定读讲的是一条记录被加了X锁其他事务仍然可以读而不被阻塞,是通过innodb的行多版本实现的,行多版本并不是实际存储多个版本记录而是通过undo实现(undo日志用来记录数据修改前的版本,回滚时会用到,用来保证事务的原子性)。一致性锁定读讲的是我可以通过SELECT语句显式地给一条记录加X锁从而保证特定应用场景下的数据一致性。 70题 数据库引擎:尤其是mysql数据库只有是InnoDB引擎的时候事物才能生效。 show engines 查看数据库默认引擎;SHOW TABLE STATUS from 数据库名字 where Name='表名' 如下;SHOW TABLE STATUS from rrz where Name='rrz_cust';修改表的引擎alter table table_name engine=innodb。 69题 如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;当然了,这个前提是,键值都是唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;同理,哈希索引也没办法利用索引完成排序,以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);哈希索引也不支持多列联合索引的最左匹配规则;B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题。 68题 decimal精度比float高,数据处理比float简单,一般优先考虑,但float存储的数据范围大,所以范围大的数据就只能用它了,但要注意一些处理细节,因为不精确可能会与自己想的不一致,也常有关于float 出错的问题。 67题 datetime、timestamp精确度都是秒,datetime与时区无关,存储的范围广(1001-9999),timestamp与时区有关,存储的范围小(1970-2038)。 66题 Char使用固定长度的空间进行存储,char(4)存储4个字符,根据编码方式的不同占用不同的字节,gbk编码方式,不论是中文还是英文,每个字符占用2个字节的空间,utf8编码方式,每个字符占用3个字节的空间。Varchar保存可变长度的字符串,使用额外的一个或两个字节存储字符串长度,varchar(10),除了需要存储10个字符,还需要1个字节存储长度信息(10),超过255的长度需要2个字节来存储。char和varchar后面如果有空格,char会自动去掉空格后存储,varchar虽然不会去掉空格,但在进行字符串比较时,会去掉空格进行比较。Varbinary保存变长的字符串,后面不会补\0。 65题 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。 64题 建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合。如果需要建立联合索引的话,还需要考虑联合索引中的顺序。此外也要考虑其他方面,比如防止过多的所有对表造成太大的压力。这些都和实际的表结构以及查询方式有关。 63题 存储过程是一些预编译的SQL语句。1、更加直白的理解:存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。2、存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全。 62题 密码散列、盐、用户身份证号等固定长度的字符串应该使用char而不是varchar来存储,这样可以节省空间且提高检索效率。 61题 推荐使用自增ID,不要使用UUID。因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降。总之,在数据量大一些的情况下,用自增主键性能会好一些。 60题 char是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容。该字段都占用10个字符,而varchar是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1,最后一个字符存储使用了多长的空间。在检索效率上来讲,char > varchar,因此在使用中,如果确定某个字段的值的长度,可以使用char,否则应该尽量使用varchar。例如存储用户MD5加密后的密码,则应该使用char。 59题 一. read uncommitted(读取未提交数据) 即便是事务没有commit,但是我们仍然能读到未提交的数据,这是所有隔离级别中最低的一种。 二. read committed(可以读取其他事务提交的数据)---大多数数据库默认的隔离级别 当前会话只能读取到其他事务提交的数据,未提交的数据读不到。 三. repeatable read(可重读)---MySQL默认的隔离级别 当前会话可以重复读,就是每次读取的结果集都相同,而不管其他事务有没有提交。 四. serializable(串行化) 其他会话对该表的写操作将被挂起。可以看到,这是隔离级别中最严格的,但是这样做势必对性能造成影响。所以在实际的选用上,我们要根据当前具体的情况选用合适的。 58题 B+树的高度一般为2-4层,所以查找记录时最多只需要2-4次IO,相对二叉平衡树已经大大降低了。范围查找时,能通过叶子节点的指针获取数据。例如查找大于等于3的数据,当在叶子节点中查到3时,通过3的尾指针便能获取所有数据,而不需要再像二叉树一样再获取到3的父节点。 57题 因为事务在修改页时,要先记 undo,在记 undo 之前要记 undo 的 redo, 然后修改数据页,再记数据页修改的 redo。 Redo(里面包括 undo 的修改) 一定要比数据页先持久化到磁盘。 当事务需要回滚时,因为有 undo,可以把数据页回滚到前镜像的状态,崩溃恢复时,如果 redo log 中事务没有对应的 commit 记录,那么需要用 undo把该事务的修改回滚到事务开始之前。 如果有 commit 记录,就用 redo 前滚到该事务完成时并提交掉。 56题 redo log是物理日志,记录的是"在某个数据页上做了什么修改"。 binlog是逻辑日志,记录的是这个语句的原始逻辑,比如"给ID=2这一行的c字段加1"。 redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。 redo log是循环写的,空间固定会用完:binlog 是可以追加写入的。"追加写"是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。 最开始 MySQL 里并没有 InnoDB 引擎,MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog日志只能用于归档。而InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统,也就是 redo log 来实现 crash-safe 能力。 55题 重做日志(redo log)      作用:确保事务的持久性,防止在发生故障,脏页未写入磁盘。重启数据库会进行redo log执行重做,达到事务一致性。 回滚日志(undo log)  作用:保证数据的原子性,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。 二进 制日志(binlog)    作用:用于主从复制,实现主从同步;用于数据库的基于时间点的还原。 错误日志(errorlog) 作用:Mysql本身启动,停止,运行期间发生的错误信息。 慢查询日志(slow query log)  作用:记录执行时间过长的sql,时间阈值可以配置,只记录执行成功。 一般查询日志(general log)    作用:记录数据库的操作明细,默认关闭,开启后会降低数据库性能 。 中继日志(relay log) 作用:用于数据库主从同步,将主库发来的bin log保存在本地,然后从库进行回放。 54题 MySQL有三种锁的级别:页级、表级、行级。 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。 死锁: 是指两个或两个以上的进程在执行过程中。因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。 死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。 那么对应的解决死锁问题的关键就是:让不同的session加锁有次序。死锁的解决办法:1.查出的线程杀死。2.设置锁的超时时间。3.指定获取锁的顺序。 53题 当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性(脏读,不可重复读,幻读等),可能产生死锁。 乐观锁:乐观锁不是数据库自带的,需要我们自己去实现。 悲观锁:在进行每次操作时都要通过获取锁才能进行对相同数据的操作。 共享锁:加了共享锁的数据对象可以被其他事务读取,但不能修改。 排他锁:当数据对象被加上排它锁时,一个事务必须得到锁才能对该数据对象进行访问,一直到事务结束锁才被释放。 行锁:就是给某一条记录加上锁。 52题 Mysql是关系型数据库,MongoDB是非关系型数据库,数据存储结构的不同。 51题 关系型数据库优点:1.保持数据的一致性(事务处理)。 2.由于以标准化为前提,数据更新的开销很小。 3. 可以进行Join等复杂查询。 缺点:1、为了维护一致性所付出的巨大代价就是其读写性能比较差。 2、固定的表结构。 3、高并发读写需求。 4、海量数据的高效率读写。 非关系型数据库优点:1、无需经过sql层的解析,读写性能很高。 2、基于键值对,数据没有耦合性,容易扩展。 3、存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,而关系型数据库则只支持基础类型。 缺点:1、不提供sql支持,学习和使用成本较高。 2、无事务处理,附加功能bi和报表等支持也不好。 redis与mongoDB的区别: 性能:TPS方面redis要大于mongodb。 可操作性:mongodb支持丰富的数据表达,索引,redis较少的网络IO次数。 可用性:MongoDB优于Redis。 一致性:redis事务支持比较弱,mongoDB不支持事务。 数据分析:mongoDB内置了数据分析的功能(mapreduce)。 应用场景:redis数据量较小的更性能操作和运算上,MongoDB主要解决海量数据的访问效率问题。 50题 如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。 49题 分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。 48题 除了缓存服务器自带的缓存失效策略之外(Redis默认的有6种策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种: 1.定时去清理过期的缓存; 2.当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。 两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,可以根据应用场景来权衡。 47题 Redis提供了两种方式来作消息队列: 一个是使用生产者消费模式模式:会让一个或者多个客户端监听消息队列,一旦消息到达,消费者马上消费,谁先抢到算谁的,如果队列里没有消息,则消费者继续监听 。另一个就是发布订阅者模式:也是一个或多个客户端订阅消息频道,只要发布者发布消息,所有订阅者都能收到消息,订阅者都是平等的。 46题 Redis的数据结构列表(list)可以实现延时队列,可以通过队列和栈来实现。blpop/brpop来替换lpop/rpop,blpop/brpop阻塞读在队列没有数据的时候,会立即进入休眠状态,一旦数据到来,则立刻醒过来。Redis的有序集合(zset)可以用于实现延时队列,消息作为value,时间作为score。Zrem 命令用于移除有序集中的一个或多个成员,不存在的成员将被忽略。当 key 存在但不是有序集类型时,返回一个错误。 45题 1.热点数据缓存:因为Redis 访问速度块、支持的数据类型比较丰富。 2.限时业务:expire 命令设置 key 的生存时间,到时间后自动删除 key。 3.计数器:incrby 命令可以实现原子性的递增。 4.排行榜:借助 SortedSet 进行热点数据的排序。 5.分布式锁:利用 Redis 的 setnx 命令进行。 6.队列机制:有 list push 和 list pop 这样的命令。 44题 一致哈希 是一种特殊的哈希算法。在使用一致哈希算法后,哈希表槽位数(大小)的改变平均只需要对 K/n 个关键字重新映射,其中K是关键字的数量, n是槽位数量。然而在传统的哈希表中,添加或删除一个槽位的几乎需要对所有关键字进行重新映射。 43题 RDB的优点:适合做冷备份;读写服务影响小,reids可以保持高性能;重启和恢复redis进程,更加快速。RDB的缺点:宕机会丢失最近5分钟的数据;文件特别大时可能会暂停数毫秒,或者甚至数秒。 AOF的优点:每个一秒执行fsync操作,最多丢失1秒钟的数据;以append-only模式写入,没有任何磁盘寻址的开销;文件过大时,不会影响客户端读写;适合做灾难性的误删除的紧急恢复。AOF的缺点:AOF日志文件比RDB数据快照文件更大,支持写QPS比RDB支持的写QPS低;比RDB脆弱,容易有bug。 42题 对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。Redis的操作之所以是原子性的,是因为Redis是单线程的。而在程序中执行多个Redis命令并非是原子性的,这也和普通数据库的表现是一样的,可以用incr或者使用Redis的事务,或者使用Redis+Lua的方式实现。对Redis来说,执行get、set以及eval等API,都是一个一个的任务,这些任务都会由Redis的线程去负责执行,任务要么执行成功,要么执行失败,这就是Redis的命令是原子性的原因。 41题 (1)twemproxy,使用方式简单(相对redis只需修改连接端口),对旧项目扩展的首选。(2)codis,目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在节点数改变情况下,旧节点数据可恢复到新hash节点。(3)redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。(4)在业务代码层实现,起几个毫无关联的redis实例,在代码层,对key进行hash计算,然后去对应的redis实例操作数据。这种方式对hash层代码要求比较高,考虑部分包括,节点失效后的代替算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。 40题 (1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件 (2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次 (3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内 (4) 尽量避免在压力很大的主库上增加从库 (5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。 39题 比如订单管理,热数据:3个月内的订单数据,查询实时性较高;温数据:3个月 ~ 12个月前的订单数据,查询频率不高;冷数据:1年前的订单数据,几乎不会查询,只有偶尔的查询需求。热数据使用mysql进行存储,需要分库分表;温数据可以存储在ES中,利用搜索引擎的特性基本上也可以做到比较快的查询;冷数据可以存放到Hive中。从存储形式来说,一般情况冷数据存储在磁带、光盘,热数据一般存放在SSD中,存取速度快,而温数据可以存放在7200转的硬盘。 38题 当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。 37题 分层架构设计,有一条准则:站点层、服务层要做到无数据无状态,这样才能任意的加节点水平扩展,数据和状态尽量存储到后端的数据存储服务,例如数据库服务或者缓存服务。显然进程内缓存违背了这一原则。 36题 更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个 jvm 内部队列中。读取数据的时候,如果发现数据不在缓存中,那么将重新读取数据+更新缓存的操作,根据唯一标识路由之后,也发送同一个 jvm 内部队列中。一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,然后一条一条的执行。 35题 redis分布式锁加锁过程:通过setnx向特定的key写入一个随机值,并同时设置失效时间,写值成功既加锁成功;redis分布式锁解锁过程:匹配随机值,删除redis上的特点key数据,要保证获取数据、判断一致以及删除数据三个操作是原子的,为保证原子性一般使用lua脚本实现;在此基础上进一步优化的话,考虑使用心跳检测对锁的有效期进行续期,同时基于redis的发布订阅优雅的实现阻塞式加锁。 34题 volatile-lru:当内存不足以容纳写入数据时,从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。 volatile-ttl:当内存不足以容纳写入数据时,从已设置过期时间的数据集中挑选将要过期的数据淘汰。 volatile-random:当内存不足以容纳写入数据时,从已设置过期时间的数据集中任意选择数据淘汰。 allkeys-lru:当内存不足以容纳写入数据时,从数据集中挑选最近最少使用的数据淘汰。 allkeys-random:当内存不足以容纳写入数据时,从数据集中任意选择数据淘汰。 noeviction:禁止驱逐数据,当内存使用达到阈值的时候,所有引起申请内存的命令会报错。 33题 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。 32题 缓存击穿,一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。如何避免:在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。 31题 缓存雪崩,是指在某一个时间段,缓存集中过期失效。大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。而缓存服务器某个节点宕机或断网,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。如何避免:1.redis高可用,搭建redis集群。2.限流降级,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。3.数据预热,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间。 30题 缓存穿透,是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。一些恶意的请求会故意查询不存在的 key,请求量很大,对数据库造成压力,甚至压垮数据库。 如何避免:1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该 key 对应的数据 insert 了之后清理缓存。2:对一定不存在的 key 进行过滤。可以把所有的可能存在的 key 放到一个大的 Bitmap 中,查询时通过该 bitmap 过滤。 29题 1.memcached 所有的值均是简单的字符串,redis 作为其替代者,支持更为丰富的数据类型。 2.redis 的速度比 memcached 快很多。 3.redis 可以持久化其数据。 4.Redis支持数据的备份,即master-slave模式的数据备份。 5.Redis采用VM机制。 6.value大小:redis最大可以达到1GB,而memcache只有1MB。 28题 Spring Boot 推荐使用 Java 配置而非 XML 配置,但是 Spring Boot 中也可以使用 XML 配置,通过spring提供的@ImportResource来加载xml配置。例如:@ImportResource({"classpath:some-context.xml","classpath:another-context.xml"}) 27题 Spring像一个大家族,有众多衍生产品例如Spring Boot,Spring Security等等,但他们的基础都是Spring的IOC和AOP,IOC提供了依赖注入的容器,而AOP解决了面向切面的编程,然后在此两者的基础上实现了其他衍生产品的高级功能。Spring MVC是基于Servlet的一个MVC框架,主要解决WEB开发的问题,因为 Spring的配置非常复杂,各种xml,properties处理起来比较繁琐。Spring Boot遵循约定优于配置,极大降低了Spring使用门槛,又有着Spring原本灵活强大的功能。总结:Spring MVC和Spring Boot都属于Spring,Spring MVC是基于Spring的一个MVC框架,而Spring Boot是基于Spring的一套快速开发整合包。 26题 YAML 是 "YAML Ain't a Markup Language"(YAML 不是一种标记语言)的递归缩写。YAML 的配置文件后缀为 .yml,是一种人类可读的数据序列化语言,可以简单表达清单、散列表,标量等数据形态。它通常用于配置文件,与属性文件相比,YAML文件就更加结构化,而且更少混淆。可以看出YAML具有分层配置数据。 25题 Spring Boot有3种热部署方式: 1.使用springloaded配置pom.xml文件,使用mvn spring-boot:run启动。 2.使用springloaded本地加载启动,配置jvm参数-javaagent:<jar包地址> -noverify。 3.使用devtools工具包,操作简单,但是每次需要重新部署。 用
游客ih62co2qqq5ww 2020-03-27 23:56:48 0 浏览量 回答数 0

回答

MongoDB ACID事务支持 这里要有一定的关系型数据库的事务的概念,不然不一定能理解的了这里说的事务概念。 下面说一说MongoDB的事务支持,这里可能会有疑惑,前面我们在介绍MongoDB时,说MongoDB是一个NoSQL数据库,不支持事务。这里又介绍MongoDB的事务。这里要说明一下MongoDB的事务支持跟关系型数据库的事务支持是两码事,如果你已经非常了解关系型数据库的事务,通过下面一副图对比MongoDB事务跟MySQL事务的不同之处。 MongoDB是如何实现事务的ACID? 1)MongoDB对原子性(Atomicity)的支持 原子性在Mongodb中到底是一个什么概念呢?为什么说支持但又说Mongodb的原子性是单行/文档级原子性,这里提供了一个MongoDB更新语句样例,如下图: MongoDB是如何实现事务的ACID? 更新“username”等于“tj.tang”的文档,更新salary、jobs、hours字段。这里对于这三个字段Mongodb在执行时要么都更新要么都不更新,这个概念在MySQL中可能你没有考虑过,但在MongoDB中由于文档可以嵌套子文档可以很复杂,所以Mongodb的原子性叫单行/文档级原子性。 对于关系型数据库的多行、多文档、多语句原子性目前Mongodb是不支持的,如下情况: MongoDB是如何实现事务的ACID? MongoDB更新条件为工资小于50万的人都把工资调整为50万,这就会牵扯到多文档更新原子性。如果当更新到Frank这个文档时,出现宕机,服务器重启之后是无法像关系型数据库那样做到数据回滚的,也就是说处理这种多文档关系型数据库事务的支持,但MongoDB不支持。那么怎么解决Mongodb这个问题呢?可以通过建模,MongoDB不是范式而是反范式的设计,通过大表和小表可以把相关的数据放到同一个文档中去。然后通过一条语句来执行操作。 2)MongoDB对一致性(consistency)的支持 对于数据一致性来说,传统数据库(单机)跟分布式数据库(MongoDB)对于数据一致性是不太一样的,怎么理解呢?如下图: MongoDB是如何实现事务的ACID? 对于传统型数据库来说,数据一致性主要是在单机上,单机的问题主要是数据进来时的规则检验,数据不能被破坏掉。而在分布式数据库上,因为他们都是多节点分布式的,我们讲的一致性往往就是讲的各个节点之间的数据是否一致。而MongoDB在这点上做的还是不错的,MongoDB支持强一致性或最终一致性(弱一致性),MongoDB的数据一致性也叫可调一致性,什么意思呢?如下图: MongoDB是如何实现事务的ACID? MongoDB的可调一致性,也就是可以自由选择强一致性或最终一致性,如果你的应用场景是前台的方式可以选择强一致性,如果你的应用场景是后台的方式(如报表)可以选择弱一致性。 一致性 上面我们讲到了通过将数据冗余存储到不同的节点来保证数据安全和减轻负载,下面我们来看看这样做引发的一个问题:保证数据在多个节点间的一致性是非常困难的。在实际应用中我们会遇到很多困难,同步节点可能会故障,甚至会无法恢复,网络可能会有延迟或者丢包,网络原因导致集群中的机器被分隔成两个不能互通的子域等等。在NoSQL中,通常有两个层次的一致性:第一种是强一致性,既集群中的所有机器状态同步保持一致。第二种是最终一致性,既可以允许短暂的数据不一致,但数据最终会保持一致。我们先来讲一下,在分布式集群中,为什么最终一致性通常是更合理的选择,然后再来讨论两种一致性的具体实现结节。 关于CAP理论 为什么我们会考虑削弱数据的一致性呢?其实这背后有一个关于分布式系统的理论依据。这个理论最早被Eric Brewer提出,称为CAP理论,尔后Gilbert和Lynch对CAP进行了理论证明。这一理论首先把分布式系统中的三个特性进行了如下归纳: 一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。 可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。 分区容忍性(P):集群中的某些节点在无法联系后,集群整体是否还能继续进行服务。 而CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。 要保证数据强一致性,最简单的方法是令写操作在所有数据节点上都执行成功才能返回成功,也就是同步概念。而这时如果某个结点出现故障,那么写操作就成功不了了,需要一直等到这个节点恢复。也就是说,如果要保证强一致性,那么就无法提供7×24的高可用性。 而要保证可用性的话,就意味着节点在响应请求时,不用完全考虑整个集群中的数据是否一致。只需要以自己当前的状态进行请求响应。由于并不保证写操作在所有节点都写成功,这可能会导致各个节点的数据状态不一致。 CAP理论导致了最终一致性和强一致性两种选择。当然,事实上还有其它的选择,比如在Yahoo的PNUTS中,采用的就是松散的一致性和弱可用性结合的方法。但是我们讨论的NoSQL系统没有类似的实现,所以我们在后续不会对其进行讨论。 强一致性 强一致性的保证,要求所有数据节点对同一个key值在同一时刻有同样的value值。虽然实际上可能某些节点存储的值是不一样的,但是作为一个整体,当客户端发起对某个key的数据请求时,整个集群对这个key对应的数据会达成一致。下面就举例说明这种一致性是如何实现的。 假设在我们的集群中,一个数据会被备份到N个结点。这N个节点中的某一个可能会扮演协调器的作用。它会保证每一个数据写操作会在成功同步到W个节点后才向客户端返回成功。而当客户端读取数据时,需要至少R个节点返回同样的数据才能返回读操作成功。而NWR之间必须要满足下面关系:R+W>N 下面举个实在的例子。比如我们设定N=3(数据会备份到A、B、C三个结点)。比如值 employee30:salary 当前的值是20000,我们想将其修改为30000。我们设定W=2,下面我们会对A、B、C三个节点发起写操作(employee30:salary, 30000),当A、B两个节点返回写成功后,协调器就会返回给客户端说写成功了。至于节点C,我们可以假设它从来没有收到这个写请求,他保存的依然是20000那个值。之后,当一个协调器执行一个对employee30:salary的读操作时,他还是会发三个请求给A、B、C三个节点: 如果设定R=1,那么当C节点先返回了20000这个值时,那我们客户端实际得到了一个错误的值。 如果设定R=2,则当协调器收到20000和30000两个值时,它会发现数据不太正确,并且会在收到第三个节点的30000的值后判断20000这个值是错误的。 所以如果要保证强一致性,在上面的应用场景中,我们需要设定R=2,W=2 如果写操作不能收到W个节点的成功返回,或者写操作不能得到R个一致的结果。那么协调器可能会在某个设定的过期时间之后向客户端返回操作失败,或者是等到系统慢慢调整到一致。这可能就导致系统暂时处于不可用状态。 对于R和W的不同设定,会导致系统在进行不同操作时需要不同数量的机器节点可用。比如你设定在所有备份节点上都写入才算写成功,既W=N,那么只要有一个备份节点故障,写操作就失败了。一般设定是R+W = N+1,这是保证强一致性的最小设定了。一些强一致性的系统设定W=N,R=1,这样就根本不用考虑各个节点数据可能不一致的情况了。 HBase是借助其底层的HDFS来实现其数据冗余备份的。HDFS采用的就是强一致性保证。在数据没有完全同步到N个节点前,写操作是不会返回成功的。也就是说它的W=N,而读操作只需要读到一个值即可,也就是说它R=1。为了不至于让写操作太慢,对多个节点的写操作是并发异步进行的。在直到所有的节点都收到了新的数据后,会自动执行一个swap操作将新数据写入。这个操作是原子性和一致性的。保证了数据在所有节点有一致的值。 最终一致性 像Voldemort,Cassandra和Riak这些类Dynamo的系统,通常都允许用户按需要设置N,R,W三个值,即使是设置成W+R<= N也是可以的。也就是说他允许用户在强一致性和最终一致性之间自由选择。而在用户选择了最终一致性,或者是W 3)MongoDB对隔离性(isolation)的支持 在关系型数据库中,SQL2定义了四种隔离级别,分别是READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。但是很少有数据库厂商遵循这些标准,比如Oracle数据库就不支持READ UNCOMMITTED和REPEATABLE READ隔离级别。而MySQL支持这全部4种隔离级别。每一种级别都规定了一个事务中所做的修改,哪些在事务内核事务外是可见的,哪些是不可见的。为了尽可能减少事务间的影响,事务隔离级别越高安全性越好但是并发就越差;事务隔离级别越低,事务请求的锁越少,或者保持锁的时间就越短,这也就是为什么绝大多数数据库系统默认的事务隔离级别是RC。 下图展示了几家不同的数据库厂商的不同事物隔离级别。 MongoDB是如何实现事务的ACID? MongoDB在3.2之前使用的是“读未提交”,这种情况下会出现“脏读”。但在MongoDB 3.2开始已经调整为“读已提交”。 下面说说每种隔离级别带来的问题: READ-UNCOMMITTED(读尚未提交的数据) 在这个级别,一个事务的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为“脏读(dirty read)”。这个级别会导致很多问题,从性能上来说,READ UNCOMMITTED不会比其他的级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。 READ-COMMITTED(读已提交的数据) 在这个级别,能满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候也叫“不可重复读(non-repeatable read)”,因为两次执行同样的查询,可能会得到不一样的结果。 REPEATABLE-READ(可重复读) 在这个级别,保证了在同一个事务中多次读取统一记录的结果是一致的。MySQL默认使用这个级别。InnoDB和XtraDB存储引擎通过多版本并发控制MVCC(multiversion concurrency control)解决了“幻读”和“不可重复读”的问题。通过前面的学习我们知道RR级别总是读取事务开始那一刻的快照信息,也就是说这些数据数据库当前状态,这在一些对于数据的时效特别敏感的业务中,就很可能会出问题。 SERIALIZABLE(串行化) 在这个级别,它通过强制事务串行执行,避免了前面说的一系列问题。简单来说,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。实际应用中也很少在本地事务中使用SERIALIABLE隔离级别,主要应用在InnoDB存储引擎的分布式事务中。 4)MongoDB对持久性(durability)的支持 对于数据持久性来说,在传统数据库中(单机)的表现为服务器任何时候发生宕机都不需要担心数据丢失的问题,因为有方式可以把数据永久保存起来了。一般都是通过日志来保证数据的持久性。通过下图来看一下传统数据库跟MongoDB对于数据持久性各自所使用的方式。 MongoDB是如何实现事务的ACID? 从上图可以看出,MongoDB同样是使用数据进来先写日志(日志刷盘的速度是非常快)然后在写入到数据库中的这种方式来保证数据的持久性,如果出现服务器宕机,当启动服务器时会从日志中读取数据。不同的是传统数据库这种方式叫做“WAL” Write-Ahead Logging(预写日志系统),而MongoDB叫做“journal”。此外MongoDB在数据持久性上这点可能做的更好,MongoDB的复制默认节点就是三节点以上的复制集群,当数据到达主节点之后会马上同步到从节点上去。
景凌凯 2019-12-02 02:05:12 0 浏览量 回答数 0

问题

【阿里云产品公测】简单日志服务SLS使用评测含教程

评测介绍 被测产品: 简单日志服务SLS评测环境: 阿里云基础ECS x2(1核, 512M, 1M)操作系统: CentOS 6.5 x64日志环境: Nginx(v1.6.2) HTTP服务器访问日志评测人: mr_wid评测时间...
mr_wid 2019-12-01 21:08:11 36639 浏览量 回答数 20

问题

标签建模

概念说明 如上文所说,标签中心的作用是在现有的数据表之上构建跨计算存储的逻辑模型,直接让用户在视图层上对数据进行管理、加工、查询,屏蔽下层的多个大数据计算存储资源,简化数据的使用。...
反向一觉 2019-12-01 21:06:40 1639 浏览量 回答数 0

问题

Data Pipeline数据如何导入?

分析型数据库支持多种数据入库方式,包括但不限于: (1)内置将MaxCompute中的海量数据快速批量导入; (2)支持标准的insert/d...
nicenelly 2019-12-01 21:25:32 1171 浏览量 回答数 0

回答

如大家所知道的,Mysql目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。 那么,这几种索引有什么功能和性能上的不同呢? FULLTEXT 即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用CREATE INDEX创建FULLTEXT索引,要比先为一张表建立FULLTEXT然后再将数据写入的速度快很多。 全文索引并不是和MyISAM一起诞生的,它的出现是为了解决WHERE name LIKE “%word%"这类针对文本的模糊查询效率较低的问题。在没有全文索引之前,这样一个查询语句是要进行遍历数据表操作的,可见,在数据量较大时是极其的耗时的,如果没有异步IO处理,进程将被挟持,很浪费时间,当然这里不对异步IO作进一步讲解,想了解的童鞋,自行谷哥。 全文索引的使用方法并不复杂: 创建ALTER TABLE table ADD INDEX FULLINDEX USING FULLTEXT(cname1[,cname2…]); 使用SELECT * FROM table WHERE MATCH(cname1[,cname2…]) AGAINST ('word' MODE ); 其中, MODE为搜寻方式(IN BOOLEAN MODE ,IN NATURAL LANGUAGE MODE ,IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION / WITH QUERY EXPANSION)。 关于这三种搜寻方式,愚安在这里也不多做交代,简单地说,就是,布尔模式,允许word里含一些特殊字符用于标记一些具体的要求,如+表示一定要有,-表示一定没有,*表示通用匹配符,是不是想起了正则,类似吧;自然语言模式,就是简单的单词匹配;含表达式的自然语言模式,就是先用自然语言模式处理,对返回的结果,再进行表达式匹配。 对搜索引擎稍微有点了解的同学,肯定知道分词这个概念,FULLTEXT索引也是按照分词原理建立索引的。西文中,大部分为字母文字,分词可以很方便的按照空格进行分割。但很明显,中文不能按照这种方式进行分词。那又怎么办呢?这个向大家介绍一个Mysql的中文分词插件Mysqlcft,有了它,就可以对中文进行分词,想了解的同学请移步Mysqlcft,当然还有其他的分词插件可以使用。 HASH Hash这个词,可以说,自打我们开始码的那一天起,就开始不停地见到和使用到了。其实,hash就是一种(key=>value)形式的键值对,如数学中的函数映射,允许多个key对应相同的value,但不允许一个key对应多个value。正是由于这个特性,hash很适合做索引,为某一列或几列建立hash索引,就会利用这一列或几列的值通过一定的算法计算出一个hash值,对应一行或几行数据(这里在概念上和函数映射有区别,不要混淆)。在java语言中,每个类都有自己的hashcode()方法,没有显示定义的都继承自object类,该方法使得每一个对象都是唯一的,在进行对象间equal比较,和序列化传输中起到了很重要的作用。hash的生成方法有很多种,足可以保证hash码的唯一性,例如在MongoDB中,每一个document都有系统为其生成的唯一的objectID(包含时间戳,主机散列值,进程PID,和自增ID)也是一种hash的表现。额,我好像扯远了-_-! 由于hash索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。那为什么还需要其他的树形索引呢? 在这里愚安就不自己总结了。引用下园子里其他大神的文章:来自 14的路 的MySQL的btree索引和hash索引的区别 (1)Hash 索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。 由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和Hash运算前完全一样。 (2)Hash 索引无法被用来避免数据的排序操作。 由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且Hash值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算; (3)Hash 索引不能利用部分索引键查询。 对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。 (4)Hash 索引在任何时候都不能避免表扫描。 前面已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。 (5)Hash 索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高。 对于选择性比较低的索引键,如果创建 Hash 索引,那么将会存在大量记录指针信息存于同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。 愚安我稍作补充,讲一下HASH索引的过程,顺便解释下上面的第4,5条: 当我们为某一列或某几列建立hash索引时(目前就只有MEMORY引擎显式地支持这种索引),会在硬盘上生成类似如下的文件: hash值 存储地址 1db54bc745a1 77#45b5 4bca452157d4 76#4556,77#45cc… … hash值即为通过特定算法由指定列数据计算出来,磁盘地址即为所在数据行存储在硬盘上的地址(也有可能是其他存储地址,其实MEMORY会将hash表导入内存)。 这样,当我们进行WHERE age = 18 时,会将18通过相同的算法计算出一个hash值==>在hash表中找到对应的储存地址==>根据存储地址取得数据。 所以,每次查询时都要遍历hash表,直到找到对应的hash值,如(4),数据量大了之后,hash表也会变得庞大起来,性能下降,遍历耗时增加,如(5)。 BTREE BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中,相信学过数据结构的童鞋都对当初学习二叉树这种数据结构的经历记忆犹新,反正愚安我当时为了软考可是被这玩意儿好好地折腾了一番,不过那次考试好像没怎么考这个。如二叉树一样,每次查询都是从树的入口root开始,依次遍历node,获取leaf。 BTREE在MyISAM里的形式和Innodb稍有不同 在 Innodb里,有两种形态:一是primary key形态,其leaf node里存放的是数据,而且不仅存放了索引键的数据,还存放了其他字段的数据。二是secondary index,其leaf node和普通的BTREE差不多,只是还存放了指向主键的信息. 而在MyISAM里,主键和其他的并没有太大区别。不过和Innodb不太一样的地方是在MyISAM里,leaf node里存放的不是主键的信息,而是指向数据文件里的对应数据行的信息. RTREE RTREE在mysql很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。 相对于BTREE,RTREE的优势在于范围查找. 各种索引的使用情况 (1)对于BTREE这种Mysql默认的索引类型,具有普遍的适用性 (2)由于FULLTEXT对中文支持不是很好,在没有插件的情况下,最好不要使用。其实,一些小的博客应用,只需要在数据采集时,为其建立关键字列表,通过关键字索引,也是一个不错的方法,至少愚安我是经常这么做的。 (3)对于一些搜索引擎级别的应用来说,FULLTEXT同样不是一个好的处理方法,Mysql的全文索引建立的文件还是比较大的,而且效率不是很高,即便是使用了中文分词插件,对中文分词支持也只是一般。真要碰到这种问题,Apache的Lucene或许是你的选择。 (4)正是因为hash表在处理较小数据量时具有无可比拟的素的优势,所以hash索引很适合做缓存(内存数据库)。如mysql数据库的内存版本Memsql,使用量很广泛的缓存工具Mencached,NoSql数据库redis等,都使用了hash索引这种形式。当然,不想学习这些东西的话Mysql的MEMORY引擎也是可以满足这种需求的。 (5)至于RTREE,愚安我至今还没有使用过,它具体怎么样,我就不知道了。有RTREE使用经历的同学,到时可以交流下! 答案来源于网络
养狐狸的猫 2019-12-02 02:18:32 0 浏览量 回答数 0

问题

Data Pipeline数据如何导入?

分析型数据库支持多种数据入库方式,包括但不限于: (1)内置将MaxCompute中的海量数据快速批量导入; (2)支持标准的insert/d...
nicenelly 2019-12-01 21:10:55 1411 浏览量 回答数 0

回答

Android平台进行数据存储的五大方式,分别如下: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存储数据 4 使用ContentProvider存储数据 5 网络存储数据 下面详细讲解这五种方式的特点 第一种: 使用SharedPreferences存储数据 适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码等 核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data/<package name>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,第二个参数具体如下: Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。 Context.MODE_WORLD_READABLE: 指定该SharedPreferences数据能被其他应用程序读,但不能写。 Context.MODE_WORLD_WRITEABLE: 指定该SharedPreferences数据能被其他应用程序读,写 Editor有如下主要重要方法: SharedPreferences.Editor clear():清空SharedPreferences里所有数据 SharedPreferences.Editor putXxx(String key , xxx value): 向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据 SharedPreferences.Editor remove(): 删除SharedPreferences中指定key对应的数据项 boolean commit(): 当Editor编辑完成后,使用该方法提交修改 实际案例:运行界面如下 这里只提供了两个按钮和一个输入文本框,布局简单,故在此不给出界面布局文件了,程序核心代码如下: 、class ViewOcl implements View.OnClickListener{ @Override public void onClick(View v) { switch(v.getId()){ case R.id.btnSet: //步骤1:获取输入值 String code = txtCode.getText().toString().trim(); //步骤2-1:创建一个SharedPreferences.Editor接口对象,lock表示要写入的XML文件名,MODE_WORLD_WRITEABLE写操作 SharedPreferences.Editor editor = getSharedPreferences("lock", MODE_WORLD_WRITEABLE).edit(); //步骤2-2:将获取过来的值放入文件 editor.putString("code", code); //步骤3:提交 editor.commit(); Toast.makeText(getApplicationContext(), "口令设置成功", Toast.LENGTH_LONG).show(); break; case R.id.btnGet: //步骤1:创建一个SharedPreferences接口对象 SharedPreferences read = getSharedPreferences("lock", MODE_WORLD_READABLE); //步骤2:获取文件中的值 String value = read.getString("code", ""); Toast.makeText(getApplicationContext(), "口令为:"+value, Toast.LENGTH_LONG).show(); break; } } } 、读写其他应用的SharedPreferences: 步骤如下 1、在创建SharedPreferences时,指定MODE_WORLD_READABLE模式,表明该SharedPreferences数据可以被其他程序读取 2、创建其他应用程序对应的Context: Context pvCount = createPackageContext("com.tony.app", Context.CONTEXT_IGNORE_SECURITY);这里的com.tony.app就是其他程序的包名 3、使用其他程序的Context获取对应的SharedPreferences SharedPreferences read = pvCount.getSharedPreferences("lock", Context.MODE_WORLD_READABLE); 4、如果是写入数据,使用Editor接口即可,所有其他操作均和前面一致。 SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。 第二种: 文件存储数据 核心原理: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。具体有以下值可选: MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可 以使用Context.MODE_APPEND MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。 MODE_WORLD_READABLE:表示当前文件可以被其他应用读取; MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。 除此之外,Context还提供了如下几个重要的方法: getDir(String name , int mode):在应用程序的数据文件夹下获取或者创建name对应的子目录 File getFilesDir():获取该应用程序的数据文件夹得绝对路径 String[] fileList():返回该应用数据文件夹的全部文件 public String read() { try { FileInputStream inStream = this.openFileInput("message.txt"); byte[] buffer = new byte[1024]; int hasRead = 0; StringBuilder sb = new StringBuilder(); while ((hasRead = inStream.read(buffer)) != -1) { sb.append(new String(buffer, 0, hasRead)); } inStream.close(); return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } public void write(String msg){ // 步骤1:获取输入值 if(msg == null) return; try { // 步骤2:创建一个FileOutputStream对象,MODE_APPEND追加模式 FileOutputStream fos = openFileOutput("message.txt", MODE_APPEND); // 步骤3:将获取过来的值放入文件 fos.write(msg.getBytes()); // 步骤4:关闭数据流 fos.close(); } catch (Exception e) { e.printStackTrace(); } } openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data//files目录,如: /data/data/cn.tony.app/files/message.txt, 下面讲解某些特殊文件读写需要注意的地方: 读写sdcard上的文件 其中读写步骤按如下进行: 1、调用Environment的getExternalStorageState()方法判断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,如下代码将返回true Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) 2、调用Environment.getExternalStorageDirectory()方法来获取外部存储器,也就是SD卡的目录,或者使用"/mnt/sdcard/"目录 3、使用IO流操作SD卡上的文件 注意点:手机应该已插入SD卡,对于模拟器而言,可通过mksdcard命令来创建虚拟存储卡 必须在AndroidManifest.xml上配置读写SD卡的权限 // 文件写操作函数 private void write(String content) { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // 如果sdcard存在 File file = new File(Environment.getExternalStorageDirectory() .toString() + File.separator + DIR + File.separator + FILENAME); // 定义File类对象 if (!file.getParentFile().exists()) { // 父文件夹不存在 file.getParentFile().mkdirs(); // 创建文件夹 } PrintStream out = null; // 打印流对象用于输出 try { out = new PrintStream(new FileOutputStream(file, true)); // 追加文件 out.println(content); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { out.close(); // 关闭打印流 } } } else { // SDCard不存在,使用Toast提示用户 Toast.makeText(this, "保存失败,SD卡不存在!", Toast.LENGTH_LONG).show(); } } // 文件读操作函数 private String read() { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // 如果sdcard存在 File file = new File(Environment.getExternalStorageDirectory() .toString() + File.separator + DIR + File.separator + FILENAME); // 定义File类对象 if (!file.getParentFile().exists()) { // 父文件夹不存在 file.getParentFile().mkdirs(); // 创建文件夹 } Scanner scan = null; // 扫描输入 StringBuilder sb = new StringBuilder(); try { scan = new Scanner(new FileInputStream(file)); // 实例化Scanner while (scan.hasNext()) { // 循环读取 sb.append(scan.next() + "\n"); // 设置文本 } return sb.toString(); } catch (Exception e) { e.printStackTrace(); } finally { if (scan != null) { scan.close(); // 关闭打印流 } } } else { // SDCard不存在,使用Toast提示用户 Toast.makeText(this, "读取失败,SD卡不存在!", Toast.LENGTH_LONG).show(); } return null; } 复制代码 第三种:SQLite存储数据 SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧 SQLiteDatabase类为我们提供了很多种方法,上面的代码中基本上囊括了大部分的数据库操作;对于添加、更新和删除来说,我们都可以使用 1 db.executeSQL(String sql); 2 db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集 除了统一的形式之外,他们还有各自的操作方法: 1 db.insert(String table, String nullColumnHack, ContentValues values); 2 db.update(String table, Contentvalues values, String whereClause, String whereArgs); 3 db.delete(String table, String whereClause, String whereArgs);以上三个方法的第一个参数都是表示要操作的表名;insert中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此列设置为NULL,不至于出现错误;insert中的第三个参数是ContentValues类型的变量,是键值对组成的Map,key代表列名,value代表该列要插入的值;update的第二个参数也很类似,只不过它是更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,比如“age > ? and age < ?”等,最后的whereArgs参数是占位符的实际参数值;delete方法的参数也是一样 下面给出demo 数据的添加 1.使用insert方法 复制代码1 ContentValues cv = new ContentValues();//实例化一个ContentValues用来装载待插入的数据2 cv.put("title","you are beautiful");//添加title3 cv.put("weather","sun"); //添加weather4 cv.put("context","xxxx"); //添加context5 String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")6 .format(new Date());7 cv.put("publish ",publish); //添加publish8 db.insert("diary",null,cv);//执行插入操作复制代码2.使用execSQL方式来实现 String sql = "insert into user(username,password) values ('Jack Johnson','iLovePopMuisc');//插入操作的SQL语句db.execSQL(sql);//执行SQL语句数据的删除 同样有2种方式可以实现 String whereClause = "username=?";//删除的条件String[] whereArgs = {"Jack Johnson"};//删除的条件参数db.delete("user",whereClause,whereArgs);//执行删除使用execSQL方式的实现 String sql = "delete from user where username='Jack Johnson'";//删除操作的SQL语句db.execSQL(sql);//执行删除操作数据修改 同上,仍是2种方式 ContentValues cv = new ContentValues();//实例化ContentValuescv.put("password","iHatePopMusic");//添加要更改的字段及内容String whereClause = "username=?";//修改条件String[] whereArgs = {"Jack Johnson"};//修改条件的参数db.update("user",cv,whereClause,whereArgs);//执行修改使用execSQL方式的实现 String sql = "update user set password = 'iHatePopMusic' where username='Jack Johnson'";//修改的SQL语句db.execSQL(sql);//执行修改数据查询 下面来说说查询操作。查询操作相对于上面的几种操作要复杂些,因为我们经常要面对着各种各样的查询条件,所以系统也考虑到这种复杂性,为我们提供了较为丰富的查询形式: 1 db.rawQuery(String sql, String[] selectionArgs); 2 db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy); 3 db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); 4 db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); 上面几种都是常用的查询方法,第一种最为简单,将所有的SQL语句都组织到一个字符串中,使用占位符代替实际参数,selectionArgs就是占位符实际参数集; 各参数说明: table:表名称colums:表示要查询的列所有名称集selection:表示WHERE之后的条件语句,可以使用占位符selectionArgs:条件语句的参数数组groupBy:指定分组的列名having:指定分组条件,配合groupBy使用orderBy:y指定排序的列名limit:指定分页参数distinct:指定“true”或“false”表示要不要过滤重复值Cursor:返回值,相当于结果集ResultSet最后,他们同时返回一个Cursor对象,代表数据集的游标,有点类似于JavaSE中的ResultSet。下面是Cursor对象的常用方法: 复制代码 1 c.move(int offset); //以当前位置为参考,移动到指定行 2 c.moveToFirst(); //移动到第一行 3 c.moveToLast(); //移动到最后一行 4 c.moveToPosition(int position); //移动到指定行 5 c.moveToPrevious(); //移动到前一行 6 c.moveToNext(); //移动到下一行 7 c.isFirst(); //是否指向第一条 8 c.isLast(); //是否指向最后一条 9 c.isBeforeFirst(); //是否指向第一条之前 10 c.isAfterLast(); //是否指向最后一条之后 11 c.isNull(int columnIndex); //指定列是否为空(列基数为0) 12 c.isClosed(); //游标是否已关闭 13 c.getCount(); //总数据项数 14 c.getPosition(); //返回当前游标所指向的行数 15 c.getColumnIndex(String columnName);//返回某列名对应的列索引值 16 c.getString(int columnIndex); //返回当前行指定列的值 复制代码实现代码 复制代码String[] params = {12345,123456};Cursor cursor = db.query("user",columns,"ID=?",params,null,null,null);//查询并获得游标if(cursor.moveToFirst()){//判断游标是否为空 for(int i=0;i<cursor.getCount();i++){ cursor.move(i);//移动到指定记录 String username = cursor.getString(cursor.getColumnIndex("username"); String password = cursor.getString(cursor.getColumnIndex("password")); } }复制代码通过rawQuery实现的带参数查询 复制代码Cursor result=db.rawQuery("SELECT ID, name, inventory FROM mytable");//Cursor c = db.rawQuery("s name, inventory FROM mytable where ID=?",new Stirng[]{"123456"}); result.moveToFirst(); while (!result.isAfterLast()) { int id=result.getInt(0); String name=result.getString(1); int inventory=result.getInt(2); // do something useful with these result.moveToNext(); } result.close();复制代码 在上面的代码示例中,已经用到了这几个常用方法中的一些,关于更多的信息,大家可以参考官方文档中的说明。 最后当我们完成了对数据库的操作后,记得调用SQLiteDatabase的close()方法释放数据库连接,否则容易出现SQLiteException。 上面就是SQLite的基本应用,但在实际开发中,为了能够更好的管理和维护数据库,我们会封装一个继承自SQLiteOpenHelper类的数据库操作类,然后以这个类为基础,再封装我们的业务逻辑方法。 这里直接使用案例讲解:下面是案例demo的界面 SQLiteOpenHelper类介绍 SQLiteOpenHelper是SQLiteDatabase的一个帮助类,用来管理数据库的创建和版本的更新。一般是建立一个类继承它,并实现它的onCreate和onUpgrade方法。 方法名 方法描述SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version) 构造方法,其中 context 程序上下文环境 即:XXXActivity.this; name :数据库名字; factory:游标工厂,默认为null,即为使用默认工厂; version 数据库版本号 onCreate(SQLiteDatabase db) 创建数据库时调用onUpgrade(SQLiteDatabase db,int oldVersion , int newVersion) 版本更新时调用getReadableDatabase() 创建或打开一个只读数据库getWritableDatabase() 创建或打开一个读写数据库首先创建数据库类 复制代码 1 import android.content.Context; 2 import android.database.sqlite.SQLiteDatabase; 3 import android.database.sqlite.SQLiteDatabase.CursorFactory; 4 import android.database.sqlite.SQLiteOpenHelper; 5 6 public class SqliteDBHelper extends SQLiteOpenHelper { 7 8 // 步骤1:设置常数参量 9 private static final String DATABASE_NAME = "diary_db";10 private static final int VERSION = 1;11 private static final String TABLE_NAME = "diary";12 13 // 步骤2:重载构造方法14 public SqliteDBHelper(Context context) {15 super(context, DATABASE_NAME, null, VERSION);16 }17 18 /*19 * 参数介绍:context 程序上下文环境 即:XXXActivity.this 20 * name 数据库名字 21 * factory 接收数据,一般情况为null22 * version 数据库版本号23 */24 public SqliteDBHelper(Context context, String name, CursorFactory factory,25 int version) {26 super(context, name, factory, version);27 }28 //数据库第一次被创建时,onCreate()会被调用29 @Override30 public void onCreate(SQLiteDatabase db) {31 // 步骤3:数据库表的创建32 String strSQL = "create table "33 + TABLE_NAME34 + "(tid integer primary key autoincrement,title varchar(20),weather varchar(10),context text,publish date)";35 //步骤4:使用参数db,创建对象36 db.execSQL(strSQL);37 }38 //数据库版本变化时,会调用onUpgrade()39 @Override40 public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {41 42 }43 }复制代码正如上面所述,数据库第一次创建时onCreate方法会被调用,我们可以执行创建表的语句,当系统发现版本变化之后,会调用onUpgrade方法,我们可以执行修改表结构等语句。 我们需要一个Dao,来封装我们所有的业务方法,代码如下: 复制代码 1 import android.content.Context; 2 import android.database.Cursor; 3 import android.database.sqlite.SQLiteDatabase; 4 5 import com.chinasoft.dbhelper.SqliteDBHelper; 6 7 public class DiaryDao { 8 9 private SqliteDBHelper sqliteDBHelper;10 private SQLiteDatabase db;11 12 // 重写构造方法13 public DiaryDao(Context context) {14 this.sqliteDBHelper = new SqliteDBHelper(context);15 db = sqliteDBHelper.getWritableDatabase();16 }17 18 // 读操作19 public String execQuery(final String strSQL) {20 try {21 System.out.println("strSQL>" + strSQL);22 // Cursor相当于JDBC中的ResultSet23 Cursor cursor = db.rawQuery(strSQL, null);24 // 始终让cursor指向数据库表的第1行记录25 cursor.moveToFirst();26 // 定义一个StringBuffer的对象,用于动态拼接字符串27 StringBuffer sb = new StringBuffer();28 // 循环游标,如果不是最后一项记录29 while (!cursor.isAfterLast()) {30 sb.append(cursor.getInt(0) + "/" + cursor.getString(1) + "/"31 + cursor.getString(2) + "/" + cursor.getString(3) + "/"32 + cursor.getString(4)+"#");33 //cursor游标移动34 cursor.moveToNext();35 }36 db.close();37 return sb.deleteCharAt(sb.length()-1).toString();38 } catch (RuntimeException e) {39 e.printStackTrace();40 return null;41 }42 43 }44 45 // 写操作46 public boolean execOther(final String strSQL) {47 db.beginTransaction(); //开始事务48 try {49 System.out.println("strSQL" + strSQL);50 db.execSQL(strSQL);51 db.setTransactionSuccessful(); //设置事务成功完成 52 db.close();53 return true;54 } catch (RuntimeException e) {55 e.printStackTrace();56 return false;57 }finally { 58 db.endTransaction(); //结束事务 59 } 60 61 }62 }复制代码我们在Dao构造方法中实例化sqliteDBHelper并获取一个SQLiteDatabase对象,作为整个应用的数据库实例;在增删改信息时,我们采用了事务处理,确保数据完整性;最后要注意释放数据库资源db.close(),这一个步骤在我们整个应用关闭时执行,这个环节容易被忘记,所以朋友们要注意。 我们获取数据库实例时使用了getWritableDatabase()方法,也许朋友们会有疑问,在getWritableDatabase()和getReadableDatabase()中,你为什么选择前者作为整个应用的数据库实例呢?在这里我想和大家着重分析一下这一点。 我们来看一下SQLiteOpenHelper中的getReadableDatabase()方法: 复制代码 1 public synchronized SQLiteDatabase getReadableDatabase() { 2 if (mDatabase != null && mDatabase.isOpen()) { 3 // 如果发现mDatabase不为空并且已经打开则直接返回 4 return mDatabase; 5 } 6 7 if (mIsInitializing) { 8 // 如果正在初始化则抛出异常 9 throw new IllegalStateException("getReadableDatabase called recursively"); 10 } 11 12 // 开始实例化数据库mDatabase 13 14 try { 15 // 注意这里是调用了getWritableDatabase()方法 16 return getWritableDatabase(); 17 } catch (SQLiteException e) { 18 if (mName == null) 19 throw e; // Can't open a temp database read-only! 20 Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e); 21 } 22 23 // 如果无法以可读写模式打开数据库 则以只读方式打开 24 25 SQLiteDatabase db = null; 26 try { 27 mIsInitializing = true; 28 String path = mContext.getDatabasePath(mName).getPath();// 获取数据库路径 29 // 以只读方式打开数据库 30 db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY); 31 if (db.getVersion() != mNewVersion) { 32 throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " 33 + mNewVersion + ": " + path); 34 } 35 36 onOpen(db); 37 Log.w(TAG, "Opened " + mName + " in read-only mode"); 38 mDatabase = db;// 为mDatabase指定新打开的数据库 39 return mDatabase;// 返回打开的数据库 40 } finally { 41 mIsInitializing = false; 42 if (db != null && db != mDatabase) 43 db.close(); 44 } 45 }复制代码在getReadableDatabase()方法中,首先判断是否已存在数据库实例并且是打开状态,如果是,则直接返回该实例,否则试图获取一个可读写模式的数据库实例,如果遇到磁盘空间已满等情况获取失败的话,再以只读模式打开数据库,获取数据库实例并返回,然后为mDatabase赋值为最新打开的数据库实例。既然有可能调用到getWritableDatabase()方法,我们就要看一下了: 复制代码public synchronized SQLiteDatabase getWritableDatabase() { if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) { // 如果mDatabase不为空已打开并且不是只读模式 则返回该实例 return mDatabase; } if (mIsInitializing) { throw new IllegalStateException("getWritableDatabase called recursively"); } // If we have a read-only database open, someone could be using it // (though they shouldn't), which would cause a lock to be held on // the file, and our attempts to open the database read-write would // fail waiting for the file lock. To prevent that, we acquire the // lock on the read-only database, which shuts out other users. boolean success = false; SQLiteDatabase db = null; // 如果mDatabase不为空则加锁 阻止其他的操作 if (mDatabase != null) mDatabase.lock(); try { mIsInitializing = true; if (mName == null) { db = SQLiteDatabase.create(null); } else { // 打开或创建数据库 db = mContext.openOrCreateDatabase(mName, 0, mFactory); } // 获取数据库版本(如果刚创建的数据库,版本为0) int version = db.getVersion(); // 比较版本(我们代码中的版本mNewVersion为1) if (version != mNewVersion) { db.beginTransaction();// 开始事务 try { if (version == 0) { // 执行我们的onCreate方法 onCreate(db); } else { // 如果我们应用升级了mNewVersion为2,而原版本为1则执行onUpgrade方法 onUpgrade(db, version, mNewVersion); } db.setVersion(mNewVersion);// 设置最新版本 db.setTransactionSuccessful();// 设置事务成功 } finally { db.endTransaction();// 结束事务 } } onOpen(db); success = true; return db;// 返回可读写模式的数据库实例 } finally { mIsInitializing = false; if (success) { // 打开成功 if (mDatabase != null) { // 如果mDatabase有值则先关闭 try { mDatabase.close(); } catch (Exception e) { } mDatabase.unlock();// 解锁 } mDatabase = db;// 赋值给mDatabase } else { // 打开失败的情况:解锁、关闭 if (mDatabase != null) mDatabase.unlock(); if (db != null) db.close(); } } }复制代码大家可以看到,几个关键步骤是,首先判断mDatabase如果不为空已打开并不是只读模式则直接返回,否则如果mDatabase不为空则加锁,然后开始打开或创建数据库,比较版本,根据版本号来调用相应的方法,为数据库设置新版本号,最后释放旧的不为空的mDatabase并解锁,把新打开的数据库实例赋予mDatabase,并返回最新实例。 看完上面的过程之后,大家或许就清楚了许多,如果不是在遇到磁盘空间已满等情况,getReadableDatabase()一般都会返回和getWritableDatabase()一样的数据库实例,所以我们在DBManager构造方法中使用getWritableDatabase()获取整个应用所使用的数据库实例是可行的。当然如果你真的担心这种情况会发生,那么你可以先用getWritableDatabase()获取数据实例,如果遇到异常,再试图用getReadableDatabase()获取实例,当然这个时候你获取的实例只能读不能写了 最后,让我们看一下如何使用这些数据操作方法来显示数据,界面核心逻辑代码: 复制代码public class SQLiteActivity extends Activity { public DiaryDao diaryDao; //因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory); //所以要确保context已初始化,我们可以把实例化Dao的步骤放在Activity的onCreate里 @Override protected void onCreate(Bundle savedInstanceState) { diaryDao = new DiaryDao(SQLiteActivity.this); initDatabase(); } class ViewOcl implements View.OnClickListener { @Override public void onClick(View v) { String strSQL; boolean flag; String message; switch (v.getId()) { case R.id.btnAdd: String title = txtTitle.getText().toString().trim(); String weather = txtWeather.getText().toString().trim();; String context = txtContext.getText().toString().trim();; String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new Date()); // 动态组件SQL语句 strSQL = "insert into diary values(null,'" + title + "','" + weather + "','" + context + "','" + publish + "')"; flag = diaryDao.execOther(strSQL); //返回信息 message = flag?"添加成功":"添加失败"; Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); break; case R.id.btnDelete: strSQL = "delete from diary where tid = 1"; flag = diaryDao.execOther(strSQL); //返回信息 message = flag?"删除成功":"删除失败"; Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); break; case R.id.btnQuery: strSQL = "select * from diary order by publish desc"; String data = diaryDao.execQuery(strSQL); Toast.makeText(getApplicationContext(), data, Toast.LENGTH_LONG).show(); break; case R.id.btnUpdate: strSQL = "update diary set title = '测试标题1-1' where tid = 1"; flag = diaryDao.execOther(strSQL); //返回信息 message = flag?"更新成功":"更新失败"; Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); break; } } } private void initDatabase() { // 创建数据库对象 SqliteDBHelper sqliteDBHelper = new SqliteDBHelper(SQLiteActivity.this); sqliteDBHelper.getWritableDatabase(); System.out.println("数据库创建成功"); } }复制代码 Android sqlite3数据库管理工具 Android SDK的tools目录下提供了一个sqlite3.exe工具,这是一个简单的sqlite数据库管理工具。开发者可以方便的使用其对sqlite数据库进行命令行的操作。 程序运行生成的.db文件一般位于"/data/data/项目名(包括所处包名)/databases/.db",因此要对数据库文件进行操作需要先找到数据库文件: 1、进入shell 命令 adb shell2、找到数据库文件 cd data/data ls --列出所有项目 cd project_name --进入所需项目名 cd databases ls --列出现寸的数据库文件 3、进入数据库 sqlite3 test_db --进入所需数据库 会出现类似如下字样: SQLite version 3.6.22Enter ".help" for instructionsEnter SQL statements terminated with a ";"sqlite>至此,可对数据库进行sql操作。 4、sqlite常用命令 .databases --产看当前数据库.tables --查看当前数据库中的表.help --sqlite3帮助.schema --各个表的生成语句 原文地址https://www.cnblogs.com/ITtangtang/p/3920916.html
auto_answer 2019-12-02 01:50:21 0 浏览量 回答数 0

问题

MaxCompute百问集锦(持续更新20171011)

大数据计算服务(MaxCompute,原名 ODPS)是一种快速、完全托管的 GB/TB/PB 级数据仓库解决方案。MaxCompute 向用户提供了完善的数据导入方案以及多种经典的分布式计算模型,能够更快速的解决用户海量数据计算问题,有效...
隐林 2019-12-01 20:19:23 38430 浏览量 回答数 18

回答

数据库课程设计 “数据库课程设计”是数据库系统及应用课程的后续实验课,是进一步巩固学生的数据库知识,加强学生的实际动手能力和提高学生综合素质。 一、 课程设计目的 课程设计为学生提供了一个既动手又动脑,独立实践的机会,将课本上的理论知识和实际有机的结合起来,锻炼学生的分析解决实际问题的能力。提高学生适应实际,实践编程的能力。课程设计的目的: 1. 加深对数据库原理、程序设计语言的理论知识的理解和应用水平; 2. 在理论和实验教学基础上进一步巩固已学基本理论及应用知识并加以综合提高; 3. 学会将知识应用于实际的方法,提高分析和解决问题的能力,增强动手能力; 4. 为毕业设计和以后工作打下必要基础。 二、课程设计要求 运用数据库原理的基本理论与应用知识,在微机RDBMS(SQL Server)的环境上建立一个数据库应用系统。要求把现实世界的事物及事物之间的复杂关系抽象为信息世界的实体及实体之间联系的信息模型,再转换为机器世界的数据模型和数据文件,并对数据文件实施检索、更新和控制等操作。 1. 用E-R图设计选定题目的信息模型; 2. 设计相应的关系模型,确定数据库结构; 3. 分析关系模式各属于第几范式,阐明理由; 4. 设计应用系统的系统结构图,确定系统功能; 5. 通过设计关系的主码约束、外码约束和使用CHECK实现完整性控制; 6. 为参照关系设计插入、删除、修改触发器; 7. 实现应用程序设计、编程、优化功能; 8. 对系统的各个应用程序进行集成和调试,进一步优化系统功能、改善系统用户界面完成实验内容所指定的各项要求; 9. 分析遇到的问题,总结并写出课程设计报告; 10. 自我评价 三、实验环境 开发环境VC++、C#、ASP或JAVA;ODBC/JDBC;数据库SQL Server 四、上机实现内容 1. 创建数据库的结构 2. 创建各基本表的结构 3. 编制系统各功能模块,完成数据的管理(增、删、改)及统计查询。对于程序运行界面不做考核的重点。 五、课程设计考核 1.对学生到实验室的情况进行不定时统计; 2.出勤率+课程设计报告+课程设计所开发的应用系统+其他(上机抽查和提问)=综合评定成绩。 3.课程设计结束时请将下列资料上交: (1) 课程设计报告; (2) 所开发的应用系统的源程序、安装和使用说明; (3) 将(1)(2)中的资料压缩成一个压缩包,压缩包文件的命名规则:班级+学号(末2位)+姓名(例如:计科090101王鹏晓); (4) 班长将本班每人的(3)中的压缩包刻录成光盘连同打印的课程设计报告收齐,交给任课教师。 附录﹑课程设计题目 题目1:课程设计选题管理系统(1,24) 包括三大模块:  课程设计题目维护与查询:题目的添加、修改和删除;按题目类型、名称和关键字查询以及已选与未选题目的查询;  学生信息维护与查询;  学生选题维护与管理:学生选题及查询; 具体功能细化:  前台学生选题:学生上网登录系统进行选题;  前台教师出题:  教师添加、修改和删除题目;  教师确认学生的选题;  后台管理出题和选题  添加用户及权限 题目2:书店管理系统(23) 包括四大模块:  售书(图书销售管理及销售统计,查询)  进书(通过书目,向发行商下定单订购图书)  库存(图书库存,统计)  相关查询 题目3:图书馆管理系统(11) 包括四大模块:  图书的查询  借书  还书  图书的预约 题目4:库存管理系统(8) 包括四大模块:  商品目录建立  商品入库管理  商品出库管理  商品库存查询 题目5:工资管理系统(1 人)41 包括四大模块:  系统数据初始化  员工基本信息数据的输入、修改、删除;  员工个人信息及工资表的查询;  员工工资的计算; 参考数据如下:  员工基本状况:包括员工号、员工姓名、性别、所在部门、工资级别、工资等级等。  工资级别和工资金额:包括工资等级、工资额。  企业部门及工作岗位信息:包括部门名称、工作岗位名称、工作岗位工资等。  工龄和工资金额:包括工龄及对应工资额。  公司福利表:包括福利名称、福利值。  工资信息:包括员工号、员工姓名、员工基础工资、员工岗位工资、员工工龄工资、公司福利、员工实得工资。 题目6:酒店客房管理系统 (1 人)14,26 包括四大模块:  前台操作:包括开房登记、退房结账和房状态查看  预订管理:包括预订房间、预订入住和解除预订  信息查询:包括在住客人列表、预订客人列表和历史客人列表  报表统计:包括开房记录统计、退房结账和预订房间统计  员工基本信息数据的输入、修改、删除; 参考数据如下:  住店管理:客人姓名、证件号码、房号、入住时期、预计离开日期、结账离开日期、应付金额  客人信息:姓名、性别、证件类型、证件号码、联系电话  房间信息:房号、房类型、价格、押金、房状态 预订房间  客人姓名、性别、房类型、房号、价格、证件类型、证件号码、联系电话、入住日期、预计离开日期、历史信息 题目7:旅行社管理信息系统(1 人)3 包括如下模块:  旅游团队、团队团员及旅游路线相关信息的输入  旅游团队、团队团员及旅游路线相关信息的维护(修改、浏览、删除和撤销)  旅游团队管理信息的查询(如按团队编号)  团队团员基本情况的查询(可选多种方式)  旅游路线相关信息的查询(如按线路编号)  旅游路线排行榜发布。  数据备份,更改密码。 参考数据如下:  团员信息表(路线编号,团队编号,团员编号,姓名,性别,电话,通信地址,身份证号码, 团费交否,备注)  线路信息表(路线名称,团费,简介,图形,路线编号)  团队信息表(团队编号,路线编号,团员人数,出发日期,返程日期)  旅游团队信息表(团队编号,团队负责人,团员人数,建团时间,是否出发,团费,盈亏) 密码信息(操作员,密码) 题目8:报刊订阅管理系统 (1 人)25,35 包括如下模块:  登录功能:登录统为身份验证登录。分为管理员登录和一般用户登录。分别通过不 同的用户名和密码进入报刊订阅管理界面,新的用户需要注册。  录入新信息功能:对于管理员,包括新用户信息和新报刊信息的录入功能,信息一旦 提交就存入到后台数据库中;普通用户自行注册进行可以修改个人信息。  订阅功能:用户可以订阅报刊,系统自动计算所需金额,并显示在界面上;管理员不 可订阅报刊,必须以用户身份订阅报刊。  查询功能:用户可以查询并显示自己所订阅的信息;管理员可以按人员、报刊、部门 分类查询。查询出的信息显示在界面上,并且可以预览和打印出结果。  统计功能:管理员可以按用户、部门、报刊统计报刊的销售情况,并对一些重要的订 阅信息进行统计;普通用户可以统计出自己的订阅情况,并且可以预览和打印出结果。  系统维护功能:数据的安全管理,主要是依靠管理员对数据库里的信息进行备份和恢 复,数据库备份后,如果出了什么意外可以恢复数据库到当时备份的状态,这提高了系统和 数据的安全性,有利于系统的维护 参考数据如下:  管理员表(Adminuser) :管理员名、密码。  部门表(Department) :部门号,部门名。  用户表(Users) :用户账号、密码、真实姓名、身 份证号、联系电话,联系地址,部门号(和部门表有关)等。  报刊类别表(NewspaperClass) :分类编号、 分类名称。  报刊信息表(Newspaper) :报刊代号、报刊名称、出版 报社、出版周期、季度报价、内容介绍、分类编号(和报刊类别表有关)等。  订单表(Order) :订单编号、用户编号、报刊代号、订阅份数、订阅月数等。 题目9:计算机等级考试教务管理系统(2 人)32 包括四大模块:  用户设置:对考点代码,考点名称进行设置,设置用户与密码;系统复位:即清除上一次考试数据(在之前存入历史)  报名管理: 报各库录入(姓名不能不空,之间不能有空格) 增加、删除、修改、浏览  准考证管理:准考证生成规则:xxx+yy+zz+kk,其中 XXX 为考点代码;YY 为语言代码,XX 为考场号,KK 为座位号 同一级别、语言应根据报名初始库信息按随机数生成准考证,同一考点最多可有 99*30=2970 名考生;如已生成准考证号,再重新生成准考证号,应该给予提示。 准考证打印  考务管理:考生信息查询、浏览、打印  成绩管理:成绩数据录入、接收 成绩合成(总成绩=笔试成绩*0.6+上机成绩*0.4),按大于或等于 60 合格 参考数据如下:  初始报名表(准考证号(为空) ,报名号(主键) ,级别+语言种类(外键) ,姓名,性别, 出生年份,民族,身份证号,联系地址,联系电话,照片,备注,参加培训)  含准考证号的报名表(准考证号(为主键) ,报名号,级别+语言种类(外键) ,姓名,性别, 出生年份,民族,身份证号,联系地址,联系电话,照片,备注,参加培训)  成绩表(准考证号,笔试成绩,上机成绩,总成绩) 级别语言代码表(级别语言代码,级别+语言)  用户信息表(考点代码,考点名称,用户名,密码) 题目10:人事管理系统(1 人)21 包括四大模块:  登录管理:包括操作员管理,口令设置,权限管理  人员管理:包括人事数据维护、人事信息查询和人事信息统计  工资管理  部门管理:包括部门表,职称表和年份表  查询及报表打印 参考数据如下:  人事表(编号,姓名,性别,出生日期,工作日期,部门代码,职称,婚否,简历,相片)  工资表(基本工资,岗位津贴,奖励,应发工资,水电,保险,实发工资)  部门表(代码,部门名称)  职称表(职称代码,职称名称)  年份表(年份代码,年份名称)  操作员表(操作员代码,操作员姓名,口令,部门,电话) 系统日志表(操作员代号,操作员姓名,登录时间,离开时间) 题目11:商品销售管理系统(1 人)19 包括四大模块:  用户登录  基本信息管理:包括销售情况、商品信息、库存表、员工表等信息的录入、浏览、修改、撤销、删除和查询等  商品销售管理:包括商品售出、退回和入库  盘点:包括库存盘点、当日销售盘点 参考数据如下:  商品信息表(商品编号,商品名称,品牌,型号,销售单价) 商品编号=类别代码(1 位)+品名代码(1 位)+品牌代码(2 位)+型号代码(2 位)  销售情况表(成交编号,商品编号,销售数量,总金额,销售日期,员工编号)  库存表(商品编号,供货商编号,进货日期,进货价,库存数量)  员工表(员工编号,员工姓名,性别,基本工资,职务,密码)  供货商表(供货商编号,供货商名称,所在地,联系电话)  员工资料表(员工编号,员工姓名,是否党员,简历,照片) 题目12:学生成绩管理系统(1 人)29 包括四大模块:  基本数据管理:包括院系管理,专业管理(设置院系下面的专业),班级管理(设置专业下面的班级),课程管理(设置相应专业下面的课程)  学生信息管理:包括基本信息录入、基本信息修改  学生成绩管理:包括学生成绩录入、学生成绩修改  信息查询:包括基本信息查询、成绩信息查询、学校人数统计  系统管理:用户管理、数据备份和系统帮助 参考数据如下:  院系信息(院系代码,院系名称)  院系专业信息(班级、院系代码,专业)  学生基本信息(班号,学号,姓名,性别,出生年月,籍贯,政治面貌,身份证号,入学年月,家庭地址,邮政编码,图片信息,备注)  学生成绩表(学号,课号,成绩,备注)  课程表(课号,课程名称,学期,备注)  班表(班号,班级名称)  用户信息表(用户名,密码,用户标识) 题目13:火车售票管理系统(4 人)36 包括四大模块:  售票管理  订票管理  信息查询  系统维护 参考数据如下:  车次信息表(车次,始发站,终点站,发车时间,到达时间)  订票信息表(车次,座位号,发车时期,发车时间,座位等级,票价)  车次座位等级分配及座位占用表(车次,座位号,座位等级,票价,占用标志)  用户信息表(用户名,密码,用户标识) 题目14:小型物业管理系统(1 人) 包括四大模块:  房源管理:对原始资料的录入、修改、查询和刷新。一般用户可以查询与房间有关 的统计资料;物业主管可其进行增、删、改、插等操作  租房管理:对房产出租,退租以及租房面积调整。其中物业主管可对其进行房租金 额计算和收款操作,一般用户对其查询  水电处理:根据租房资料,结合当月水、电量进行分摊,完成应收水电费。其中物 业主管对其进行计算,其他查询  交款处理:提供收款和发票打印以及交款数据查询  查询处理:对租房资料、交款资料,发票资料进行查询 参考数据如下:  房源资料(名称,面积,月租,物业,仓库)  租房资料(名称,面积,单位,月租,物业,押金,仓库)  水电资料(单位,电量,水量,电费,水费)  交费资料(收费项目,应收日期,应收金额,已收金额,未收金额,本次收款)  发票资料(单位,房租,电费,水费,物业)  权限资料(用户,密码,房源管理,租房管理,水电管理,交费管理,发票管理,系统维护) 其中系统管理员,有权进行系统维护;单位内部物业主管,有权进行物业资源调配、单元出 租,退租和收款开票操作;物业管理员,有权进行水电处理和收款处理等操行;租户代表, 有权进行种类费的查询操作 题目15:机房收费管理系统(1 人)7,34 包括四大模块:  登录模块  上机管理模块 说明:上机登记时,余额不足 3 元或卡处于挂失状态,则拒绝登记 每位同学的一次上机形成一条记录,每 36S 遍历一次上机记录表,对表中所有正上机字段为 TRUE 的记录的上机用时增加 36S,同时从上机卡表的余额减少  上机卡管理模块  充值挂失模块  查找统计模块:统计某天上机的总时数、每次上机的平均时数和机房的收入;某学 生上机的次数、上机总时数、每次上机平均时间;挂失和查询余 参考数据如下:  上机卡(卡号,姓名,专业班级,余额,状态) 状态的取值有:正常(能自费上机)  挂失上机记录(卡号,上机日期,开始时间,上机用时,正上机,管理号代码),上机用时记录学生上机时间(S);正上机是一个布尔型,为 True 表示正上机,每 36 秒刷新 其上机用时并扣除上机费用,为 False 表示上机结束。上机记录表永久保存,用于事后查询 和统计 管理员(代码,姓名,口令)  题目16:高校药房管理(1 人)31 包括四大模块:  基础数据处理:包括医生和药剂师名单的录入,修改,删除及查询  营业数据处理:包括药品进货上柜,处理划价,配药,柜存药品查询,处方综合查 询,交接班结转清。 参考数据如下:  药品信息表(货号,货名,计量单位,进货数量,进货单价,出售单价,进货日期,收货人 和供应商)  处方信息(编号,患者姓名,医生姓名,药剂师姓名,处方日期,配药日期) 处方药品信息(处方编号,药品货号,计量单位,配药数量,销售单价,已配药否)  医生名单和药剂师名单表(姓名)  题目17:考勤管理系统(2 人)40 包括四大模块:  记录每个员工每天所有进入公司的时刻和离开公司的时刻。  每天结束时自动统计当天的工作时间  每天结束时自动统计当天迟到或早退的次数。  对于弹性工作制,每天结束时自动统计当月的工时,并自动算出当月欠缺或富余的 时间  每个月末统计该月的工作时间判断是束足够  每个月末统计该月的工作天数并判断是否足够  管理人员查询并修改工作时间(特殊情况下修改)  管理人员账户管理(如设置密码等)  管理人员设定早退及迟到的条件,每个月的工作时间  管理人员设定每个月的工作日期及放假日期 参考数据如下:  员工信息(工号,姓名,年龄,入职时间,职位,性别,密码)  配置信息(上班时间小时,上班时间分钟,下班时间小时,下班时间分钟,每天工作时间)  每月统计数据表(工号,姓名,剩余的时间,迟到的次数,早退的次数,工作天数)  每天统计信息表(工号,姓名,小时,分钟,动作,时间) 其中动作指的时入或离开公司  题目18:单位房产管理系统(2 人)33,10 包括四大模块:  系统模块:完成数据库维护、系统关闭功能  物业费用模块:完成本月物业的计费、历史资料查询和财务部门接口传送数据、物 业相关费用单价设置  房屋资源模块:对房屋资源进行添加、列表显示、查询  职工信息模块:对职工进行添加、列表显示、查询以及相应部门、职务进行维护  帮助模块:对用户使用本系统提供在线帮助 参考数据如下:  职工(编号,姓名,性别,参加工作时间,行政职务,专业技术职务,评上最高行政职务时 间,评上最高专业技术职务时间,双职工姓名,现居住房号,档案号,房产证号,所在部门 编号,是否为户主)  部门(编号,部门名称) 住房级别表(编号,级别,住房标准,控制标准,级别分类)  房产情况(编号,房号,使用面积,现居住人 id,上一个居住人 id,最早居住人 ID,阳台面积)  物业费用(编号,房号,水基数,水现在值,电基数,电现在值,燃气基数,燃气现在值, 当前年份,当前月份)  价格标准(编号,水单价,电单价,燃气单价) 题目19:标准化考试系统 (2 人)15,39 功能要求: 设计一个简单的标准化考试系统,仅有单项选择题、多项选择题和判断题功能即可。 包括四大模块:  题库管理:实现试题的录入、修改、删除功能;  考试子系统:能够实现考生做题、结果自动存入到数据库中,有时间提示;  选择身份(登录)功能:系统能够记录考生输入的登录信息及交卷信息;  自动评分功能:考生交卷后能自动评分;  查看成绩功能:能够查询考生相关信息(包含成绩等)。 参考数据如下: 其它可供选择的题目: 网上教务评教系统130,127,133 16 学生日常行为评分管理系统232,110,230 网上鲜花店 38 基于BS结构的工艺品销售系统12 基于BS结构的校园二手物品交易网站 37 大学生就业管理系统201,208,234 题库及试卷管理系统 数据库原理及应用 课程设计报告 题目: 课程设计选题管理系统 所在学院: 班 级: 学 号: 姓 名: 李四 指导教师: 2011年12月 日 目录 一、 概述 二、需求分析 三、概念设计 四、逻辑设计 五、系统实现 六、小结 一、概述
玄学酱 2019-12-02 01:22:25 0 浏览量 回答数 0

问题

肇庆开诊断证明-qyo

肇庆开诊断证明-qyo(微)电〗【186-6605-3854〗因为我需要将flink处理结果输出到本地文件,在集群模式下,能否指定某一个固定节点来执行输出文件的task呢? writeAsForma...
游客5k2abgdj3m2ti 2019-12-01 22:09:09 3 浏览量 回答数 0

回答

*1、查询SQL尽量不要使用select ,而是select具体字段。 反例子: select * from employee; 正例子: select id,name from employee; 理由: 只取需要的字段,节省资源、减少网络开销。select * 进行查询时,很可能就不会使用到覆盖索引了,就会造成回表查询。 2、如果知道查询结果只有一条或者只要最大/最小一条记录,建议用limit 1 假设现在有employee员工表,要找出一个名字叫jay的人. CREATE TABLE `employee` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `date` datetime DEFAULT NULL, `sex` int(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 反例: select id,name from employee where name='jay' 正例 select id,name from employee where name='jay' limit 1; 理由: 加上limit 1后,只要找到了对应的一条记录,就不会继续向下扫描了,效率将会大大提高。当然,如果name是唯一索引的话,是不必要加上limit 1了,因为limit的存在主要就是为了防止全表扫描,从而提高性能,如果一个语句本身可以预知不用全表扫描,有没有limit ,性能的差别并不大。 3、应尽量避免在where子句中使用or来连接条件 新建一个user表,它有一个普通索引userId,表结构如下: CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userId` int(11) NOT NULL, `age` int(11) NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`), KEY `idx_userId` (`userId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 假设现在需要查询userid为1或者年龄为18岁的用户,很容易有以下sql 反例: select * from user where userid=1 or age =18 正例: //使用union all select * from user where userid=1 union all select * from user where age = 18 //或者分开两条sql写: select * from user where userid=1 select * from user where age = 18 理由: 使用or可能会使索引失效,从而全表扫描。 对于or+没有索引的age这种情况,假设它走了userId的索引,但是走到age查询条件时,它还得全表扫描,也就是需要三步过程: 全表扫描+索引扫描+合并 如果它一开始就走全表扫描,直接一遍扫描就完事。 mysql是有优化器的,处于效率与成本考虑,遇到or条件,索引可能失效,看起来也合情合理。 4、优化limit分页 我们日常做分页需求时,一般会用 limit 实现,但是当偏移量特别大的时候,查询效率就变得低下。 反例: select id,name,age from employee limit 10000,10 正例: //方案一 :返回上次查询的最大记录(偏移量) select id,name from employee where id>10000 limit 10. //方案二:order by + 索引 select id,name from employee order by id limit 10000,10 //方案三:在业务允许的情况下限制页数: 理由: 当偏移量最大的时候,查询效率就会越低,因为Mysql并非是跳过偏移量直接去取后面的数据,而是先把偏移量+要取的条数,然后再把前面偏移量这一段的数据抛弃掉再返回的。 如果使用优化方案一,返回上次最大查询记录(偏移量),这样可以跳过偏移量,效率提升不少。 方案二使用order by+索引,也是可以提高查询效率的。 方案三的话,建议跟业务讨论,有没有必要查这么后的分页啦。因为绝大多数用户都不会往后翻太多页。 5、优化你的like语句 日常开发中,如果用到模糊关键字查询,很容易想到like,但是like很可能让你的索引失效。 反例: select userId,name from user where userId like '%123'; 正例: select userId,name from user where userId like '123%'; 理由: 把%放前面,并不走索引,如下: 把% 放关键字后面,还是会走索引的。如下: 6、使用where条件限定要查询的数据,避免返回多余的行 假设业务场景是这样:查询某个用户是否是会员。曾经看过老的实现代码是这样。。。 反例: List<Long> userIds = sqlMap.queryList("select userId from user where isVip=1"); boolean isVip = userIds.contains(userId); 正例: Long userId = sqlMap.queryObject("select userId from user where userId='userId' and isVip='1' ") boolean isVip = userId!=null; 理由: 需要什么数据,就去查什么数据,避免返回不必要的数据,节省开销。 7、尽量避免在索引列上使用mysql的内置函数 业务需求:查询最近七天内登陆过的用户(假设loginTime加了索引) 反例: select userId,loginTime from loginuser where Date_ADD(loginTime,Interval 7 DAY) >=now(); 正例: explain select userId,loginTime from loginuser where loginTime >= Date_ADD(NOW(),INTERVAL - 7 DAY); 理由: 索引列上使用mysql的内置函数,索引失效 8、应尽量避免在 where 子句中对字段进行表达式操作,这将导致系统放弃使用索引而进行全表扫 反例: select * from user where age-1 =10; 正例: select * from user where age =11; 理由: 9、Inner join 、left join、right join,优先使用Inner join,如果是left join,左边表结果尽量小 Inner join 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集 left join 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。 right join 在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。 都满足SQL需求的前提下,推荐优先使用Inner join(内连接),如果要使用left join,左边表数据结果尽量小,如果有条件的尽量放到左边处理。 反例: select * from tab1 t1 left join tab2 t2 on t1.size = t2.size where t1.id>2; 正例: select * from (select * from tab1 where id >2) t1 left join tab2 t2 on t1.size = t2.size; 理由: 如果inner join是等值连接,或许返回的行数比较少,所以性能相对会好一点。 同理,使用了左连接,左边表数据结果尽量小,条件尽量放到左边处理,意味着返回的行数可能比较少。 10、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。 反例: select age,name from user where age <>18; 正例: //可以考虑分开两条sql写 select age,name from user where age <18; select age,name from user where age >18; 理由: 使用!=和<>很可能会让索引失效 11、使用联合索引时,注意索引列的顺序,一般遵循最左匹配原则。 表结构:(有一个联合索引idx_userid_age,userId在前,age在后) CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userId` int(11) NOT NULL, `age` int(11) DEFAULT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`), KEY `idx_userid_age` (`userId`,`age`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 反例: select * from user where age = 10; 正例: //符合最左匹配原则 select * from user where userid=10 and age =10; //符合最左匹配原则 select * from user where userid =10; 理由: 当我们创建一个联合索引的时候,如(k1,k2,k3),相当于创建了(k1)、(k1,k2)和(k1,k2,k3)三个索引,这就是最左匹配原则。 联合索引不满足最左原则,索引一般会失效,但是这个还跟Mysql优化器有关的。 12、对查询进行优化,应考虑在 where 及 order by 涉及的列上建立索引,尽量避免全表扫描。 反例: select * from user where address ='深圳' order by age ; 正例: 添加索引 alter table user add index idx_address_age (address,age) 13、如果插入数据过多,考虑批量插入。 反例: for(User u :list){ INSERT into user(name,age) values(#name#,#age#) } 正例: //一次500批量插入,分批进行 insert into user(name,age) values <foreach collection="list" item="item" index="index" separator=","> (#{item.name},#{item.age}) </foreach> 理由: 批量插入性能好,更加省时间 打个比喻:假如你需要搬一万块砖到楼顶,你有一个电梯,电梯一次可以放适量的砖(最多放500),你可以选择一次运送一块砖,也可以一次运送500,你觉得哪个时间消耗大? 14、在适当的时候,使用覆盖索引。 覆盖索引能够使得你的SQL语句不需要回表,仅仅访问索引就能够得到所有需要的数据,大大提高了查询效率。 反例: // like模糊查询,不走索引了 select * from user where userid like '%123%' 正例: //id为主键,那么为普通索引,即覆盖索引登场了。 select id,name from user where userid like '%123%'; 15、慎用distinct关键字 distinct 关键字一般用来过滤重复记录,以返回不重复的记录。在查询一个字段或者很少字段的情况下使用时,给查询带来优化效果。但是在字段很多的时候使用,却会大大降低查询效率。 反例: SELECT DISTINCT * from user; 正例: select DISTINCT name from user; 理由: 带distinct的语句cpu时间和占用时间都高于不带distinct的语句。因为当查询很多字段时,如果使用distinct,数据库引擎就会对数据进行比较,过滤掉重复数据,然而这个比较,过滤的过程会占用系统资源,cpu时间。 16、删除冗余和重复索引 反例: KEY `idx_userId` (`userId`) KEY `idx_userId_age` (`userId`,`age`) 正例: //删除userId索引,因为组合索引(A,B)相当于创建了(A)和(A,B)索引 KEY `idx_userId_age` (`userId`,`age`) 理由: 重复的索引需要维护,并且优化器在优化查询的时候也需要逐个地进行考虑,这会影响性能的。 17、如果数据量较大,优化你的修改/删除语句。 避免同时修改或删除过多数据,因为会造成cpu利用率过高,从而影响别人对数据库的访问。 反例: //一次删除10万或者100万+? delete from user where id <100000; //或者采用单一循环操作,效率低,时间漫长 for(User user:list){ delete from user; } 正例: //分批进行删除,如每次500 delete user where id<500 delete product where id>=500 and id<1000; 理由: 一次性删除太多数据,可能会有lock wait timeout exceed的错误,所以建议分批操作。 18、where子句中考虑使用默认值代替null。 反例: select * from user where age is not null; 正例: //设置0为默认值 select * from user where age>0; 理由: 并不是说使用了is null 或者 is not null 就会不走索引了,这个跟mysql版本以及查询成本都有关。 如果mysql优化器发现,走索引比不走索引成本还要高,肯定会放弃索引,这些条件!=,>is null,is not null经常被认为让索引失效,其实是因为一般情况下,查询的成本高,优化器自动放弃的。 如果把null值,换成默认值,很多时候让走索引成为可能,同时,表达意思会相对清晰一点。 19、不要有超过5个以上的表连接 连表越多,编译的时间和开销也就越大。 把连接表拆开成较小的几个执行,可读性更高。 如果一定需要连接很多表才能得到数据,那么意味着糟糕的设计了。 20、exist & in的合理利用 假设表A表示某企业的员工表,表B表示部门表,查询所有部门的所有员工,很容易有以下SQL: select * from A where deptId in (select deptId from B); 这样写等价于: 先查询部门表B select deptId from B 再由部门deptId,查询A的员工 select * from A where A.deptId = B.deptId 可以抽象成这样的一个循环: List<> resultSet ; for(int i=0;i<B.length;i++) { for(int j=0;j<A.length;j++) { if(A[i].id==B[j].id) { resultSet.add(A[i]); break; } } } 显然,除了使用in,我们也可以用exists实现一样的查询功能,如下: select * from A where exists (select 1 from B where A.deptId = B.deptId); 因为exists查询的理解就是,先执行主查询,获得数据后,再放到子查询中做条件验证,根据验证结果(true或者false),来决定主查询的数据结果是否得意保留。 那么,这样写就等价于: select * from A,先从A表做循环 select * from B where A.deptId = B.deptId,再从B表做循环. 同理,可以抽象成这样一个循环: List<> resultSet ; for(int i=0;i<A.length;i++) { for(int j=0;j<B.length;j++) { if(A[i].deptId==B[j].deptId) { resultSet.add(A[i]); break; } } } 数据库最费劲的就是跟程序链接释放。假设链接了两次,每次做上百万次的数据集查询,查完就走,这样就只做了两次;相反建立了上百万次链接,申请链接释放反复重复,这样系统就受不了了。即mysql优化原则,就是小表驱动大表,小的数据集驱动大的数据集,从而让性能更优。 因此,我们要选择最外层循环小的,也就是,如果B的数据量小于A,适合使用in,如果B的数据量大于A,即适合选择exist。 21、尽量用 union all 替换 union 如果检索结果中不会有重复的记录,推荐union all 替换 union。 反例: select * from user where userid=1 union select * from user where age = 10 正例: select * from user where userid=1 union all select * from user where age = 10 理由: 如果使用union,不管检索结果有没有重复,都会尝试进行合并,然后在输出最终结果前进行排序。如果已知检索结果没有重复记录,使用union all 代替union,这样会提高效率。 22、索引不宜太多,一般5个以内。 索引并不是越多越好,索引虽然提高了查询的效率,但是也降低了插入和更新的效率。 insert或update时有可能会重建索引,所以建索引需要慎重考虑,视具体情况来定。 一个表的索引数最好不要超过5个,若太多需要考虑一些索引是否没有存在的必要。 23、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型 反例: king_id` varchar(20) NOT NULL COMMENT '守护者Id' 正例: `king_id` int(11) NOT NULL COMMENT '守护者Id'` 理由: 相对于数字型字段,字符型会降低查询和连接的性能,并会增加存储开销。 24、索引不适合建在有大量重复数据的字段上,如性别这类型数据库字段。 因为SQL优化器是根据表中数据量来进行查询优化的,如果索引列有大量重复数据,Mysql查询优化器推算发现不走索引的成本更低,很可能就放弃索引了。 25、尽量避免向客户端返回过多数据量。 假设业务需求是,用户请求查看自己最近一年观看过的直播数据。 反例: //一次性查询所有数据回来 select * from LivingInfo where watchId =useId and watchTime >= Date_sub(now(),Interval 1 Y) 正例: //分页查询 select * from LivingInfo where watchId =useId and watchTime>= Date_sub(now(),Interval 1 Y) limit offset,pageSize //如果是前端分页,可以先查询前两百条记录,因为一般用户应该也不会往下翻太多页, select * from LivingInfo where watchId =useId and watchTime>= Date_sub(now(),Interval 1 Y) limit 200 ; 26、当在SQL语句中连接多个表时,请使用表的别名,并把别名前缀于每一列上,这样语义更加清晰。 反例: select * from A inner join B on A.deptId = B.deptId; 正例: select memeber.name,deptment.deptName from A member inner join B deptment on member.deptId = deptment.deptId; 27、尽可能使用varchar/nvarchar 代替 char/nchar。 反例: `deptName` char(100) DEFAULT NULL COMMENT '部门名称' 正例: `deptName` varchar(100) DEFAULT NULL COMMENT '部门名称' 理由: 因为首先变长字段存储空间小,可以节省存储空间。 其次对于查询来说,在一个相对较小的字段内搜索,效率更高。 28、为了提高group by 语句的效率,可以在执行到该语句前,把不需要的记录过滤掉。 反例: select job,avg(salary) from employee group by job having job ='president' or job = 'managent' 正例: select job,avg(salary) from employee where job ='president' or job = 'managent' group by job; 29、如何字段类型是字符串,where时一定用引号括起来,否则索引失效 反例: select * from user where userid =123; 正例: select * from user where userid ='123'; 理由: 为什么第一条语句未加单引号就不走索引了呢? 这是因为不加单引号时,是字符串跟数字的比较,它们类型不匹配,MySQL会做隐式的类型转换,把它们转换为浮点数再做比较。 30、使用explain 分析你SQL的计划 日常开发写SQL的时候,尽量养成一个习惯吧。用explain分析一下你写的SQL,尤其是走不走索引这一块。 explain select * from user where userid =10086 or age =18;
剑曼红尘 2020-04-21 14:01:32 0 浏览量 回答数 0

问题

如何保证缓存与数据库的双写一致性?【Java问答】38期

面试题 如何保证缓存与数据库的双写一致性? 面试官心理分析 你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解...
剑曼红尘 2020-06-16 12:58:57 36 浏览量 回答数 1

问题

【精品问答】带你进入数据库领域

表格存储 Tablestore 的错误码有哪些? https://developer.aliyun.com/ask/280370 存储数据量对查询速度有影响吗? https://developer.aliyun...
谙忆 2020-04-07 20:45:48 12 浏览量 回答数 1

问题

干货分享:DBA专家门诊一期:索引与sql优化问题汇总

各位亲爱的云友,               非常感谢大家踊跃参加DBA专家门诊一期:索引与sql优化,很多云友都提出了自己的问题,门诊主任医师玄惭对大家提的问题一一作了解答。现已整...
xiaofanqie 2019-12-01 21:24:21 74007 浏览量 回答数 38

回答

流处理,听起来很高大上啊,其实就是分块读取。有这么一些情况,有一个很大的几个G的文件,没办法一次处理,那么就分批次处理,一次处理1百万行,接着处理下1百万行,慢慢地总是能处理完的。 使用类似迭代器的方式 data=pd.read_csv(file, chunksize=1000000)for sub_df in data: print('do something in sub_df here') 1234索引 Series和DataFrame都是有索引的,索引的好处是快速定位,在涉及到两个Series或DataFrame时可以根据索引自动对齐,比如日期自动对齐,这样可以省去很多事。 缺失值 pd.isnull(obj)obj.isnull()12将字典转成数据框,并赋予列名,索引 DataFrame(data, columns=['col1','col2','col3'...], index = ['i1','i2','i3'...]) 12查看列名 DataFrame.columns 查看索引 DataFrame.index 重建索引 obj.reindex(['a','b','c','d','e'...], fill_value=0] 按给出的索引顺序重新排序,而不是替换索引。如果索引没有值,就用0填充 就地修改索引 data.index=data.index.map(str.upper)12345列顺序重排(也是重建索引) DataFrame.reindex[columns=['col1','col2','col3'...])` 也可以同时重建index和columns DataFrame.reindex[index=['a','b','c'...],columns=['col1','col2','col3'...])12345重建索引的快捷键 DataFrame.ix[['a','b','c'...],['col1','col2','col3'...]]1重命名轴索引 data.rename(index=str.title,columns=str.upper) 修改某个索引和列名,可以通过传入字典 data.rename(index={'old_index':'new_index'}, columns={'old_col':'new_col'}) 12345查看某一列 DataFrame['state'] 或 DataFrame.state1查看某一行 需要用到索引 DataFrame.ix['index_name']1添加或删除一列 DataFrame['new_col_name'] = 'char_or_number' 删除行 DataFrame.drop(['index1','index2'...]) 删除列 DataFrame.drop(['col1','col2'...],axis=1) 或 del DataFrame['col1']1234567DataFrame选择子集 类型 说明obj[val] 选择一列或多列obj.ix[val] 选择一行或多行obj.ix[:,val] 选择一列或多列obj.ix[val1,val2] 同时选择行和列reindx 对行和列重新索引icol,irow 根据整数位置选取单列或单行get_value,set_value 根据行标签和列标签选择单个值针对series obj[['a','b','c'...]]obj['b':'e']=512针对dataframe 选择多列 dataframe[['col1','col2'...]] 选择多行 dataframe[m:n] 条件筛选 dataframe[dataframe['col3'>5]] 选择子集 dataframe.ix[0:3,0:5]1234567891011dataframe和series的运算 会根据 index 和 columns 自动对齐然后进行运算,很方便啊 方法 说明add 加法sub 减法div 除法mul 乘法 没有数据的地方用0填充空值 df1.add(df2,fill_value=0) dataframe 与 series 的运算 dataframe - series 规则是: -------- v 指定轴方向 dataframe.sub(series,axis=0)规则是:-------- --- | | | | ----->| | | | | | | | | | | | -------- ---12345678910111213141516171819202122apply函数 f=lambda x:x.max()-x.min() 默认对每一列应用 dataframe.apply(f) 如果需要对每一行分组应用 dataframe.apply(f,axis=1)1234567排序和排名 默认根据index排序,axis = 1 则根据columns排序 dataframe.sort_index(axis=0, ascending=False) 根据值排序 dataframe.sort_index(by=['col1','col2'...]) 排名,给出的是rank值 series.rank(ascending=False) 如果出现重复值,则取平均秩次 在行或列上面的排名 dataframe.rank(axis=0)12345678910111213描述性统计 方法 说明count 计数describe 给出各列的常用统计量min,max 最大最小值argmin,argmax 最大最小值的索引位置(整数)idxmin,idxmax 最大最小值的索引值quantile 计算样本分位数sum,mean 对列求和,均值mediam 中位数mad 根据平均值计算平均绝对离差var,std 方差,标准差skew 偏度(三阶矩)Kurt 峰度(四阶矩)cumsum 累积和Cummins,cummax 累计组大致和累计最小值cumprod 累计积diff 一阶差分pct_change 计算百分数变化唯一值,值计数,成员资格 obj.unique()obj.value_count()obj.isin(['b','c'])123处理缺失值 过滤缺失值 只要有缺失值就丢弃这一行 dataframe.dropna() 要求全部为缺失才丢弃这一行 dataframe.dropna(how='all') 根据列来判断 dataframe.dropna(how='all',axis=1) 填充缺失值 1.用0填充 df.fillna(0) 2.不同的列用不同的值填充 df.fillna({1:0.5, 3:-1}) 3.用均值填充 df.fillna(df.mean()) 此时axis参数同前面, 123456789101112131415161718192021将列转成行索引 df.set_index(['col1','col2'...])1数据清洗,重塑 合并数据集 取 df1,df2 都有的部分,丢弃没有的 默认是inner的连接方式 pd.merge(df1,df2, how='inner') 如果df1,df2的连接字段名不同,则需要特别指定 pd.merge(df1,df2,left_on='l_key',right_on='r_key') 其他的连接方式有 left,right, outer等。 如果dataframe是多重索引,根据多个键进行合并 pd.merge(left, right, on=['key1','key2'],how = 'outer') 合并后如果有重复的列名,需要添加后缀 pd.merge(left, right, on='key1', suffixes=('_left','_right'))1234567891011121314索引上的合并 针对dataframe中的连接键不是列名,而是索引名的情况。 pd.merge(left, right, left_on = 'col_key', right_index=True) 即左边的key是列名,右边的key是index。 多重索引 pd.merge(left, right, left_on=['key1','key2'], right_index=True)123456dataframe的join方法 实现按索引合并。 其实这个join方法和数据库的join函数是以一样的理解 left.join(right, how='outer') 一次合并多个数据框 left.join([right1,right2],how='outer')123456轴向连接(更常用) 连接:concatenation 绑定:binding 堆叠:stacking列上的连接 np.concatenation([df1,df2],axis=1) #np包pd.concat([df1,df2], axis=1) #pd包 和R语言中的 cbind 是一样的 如果axis=0,则和 rbind 是一样的 索引对齐,没有的就为空 join='inner' 得到交集 pd.concat([df1,df2], axis=1, join='innner') keys 参数,还没看明白 ignore_index=True,如果只是简单的合并拼接而不考虑索引问题。 pd.concat([df1,df2],ignore_index=True)123456789101112131415合并重复数据 针对可能有索引全部或者部分重叠的两个数据集 填充因为合并时索引赵成的缺失值 where函数 where即if-else函数 np.where(isnull(a),b,a)12combine_first方法 如果a中值为空,就用b中的值填补 a[:-2].combine_first(b[2:]) combine_first函数即对数据打补丁,用df2的数据填充df1中的缺失值 df1.combine_first(df2)12345重塑层次化索引 stact:将数据转为长格式,即列旋转为行 unstack:转为宽格式,即将行旋转为列result=data.stack()result.unstack()12长格式转为宽格式 pivoted = data.pivot('date','item','value') 前两个参数分别是行和列的索引名,最后一个参数则是用来填充dataframe的数据列的列名。如果忽略最后一个参数,得到的dataframe会带有层次化的列。 123透视表 table = df.pivot_table(values=["Price","Quantity"], index=["Manager","Rep"], aggfunc=[np.sum,np.mean], margins=True)) values:需要对哪些字段应用函数 index:透视表的行索引(row) columns:透视表的列索引(column) aggfunc:应用什么函数 fill_value:空值填充 margins:添加汇总项 然后可以对透视表进行筛选 table.query('Manager == ["Debra Henley"]')table.query('Status == ["pending","won"]')123456789101112131415移除重复数据 判断是否重复 data.duplicated()` 移除重复数据 data.drop_duplicated() 对指定列判断是否存在重复值,然后删除重复数据 data.drop_duplicated(['key1'])123456789交叉表 是一种用于计算分组频率的特殊透视表. 注意,只对离散型的,分类型的,字符型的有用,连续型数据是不能计算频率这种东西的。 pd.crosstab(df.col1, df.col2, margins=True)1类似vlookup函数 利用函数或映射进行数据转换 1.首先定义一个字典 meat_to_animal={ 'bacon':'pig', 'pulled pork':'pig', 'honey ham':'cow' } 2.对某一列应用一个函数,或者字典,顺便根据这一列的结果创建新列 data['new_col']=data['food'].map(str.lower).map(meat_to_animal)123456789替换值 data.replace(-999,np.na) 多个值的替换 data.replace([-999,-1000],np.na) 对应替换 data.replace([-999,-1000],[np.na,0]) 对应替换也可以传入一个字典 data.replace({-999:np.na,-1000:0})123456789离散化 定义分割点 简单分割(等宽分箱) s=pd.Series(range(100))pd.cut(s, bins=10, labels=range(10)) bins=[20,40,60,80,100] 切割 cats = pd.cut(series,bins) 查看标签 cats.labels 查看水平(因子) cats.levels 区间计数 pd.value_count(cats) 自定义分区的标签 group_names=['youth','youngAdult','MiddleAge','Senior']pd.cut(ages,bins,labels=group_names)1234567891011121314151617181920212223分位数分割 data=np.random.randn(1000)pd.qcut(data,4) #四分位数 自定义分位数,包含端点 pd.qcut(data,[0,0.3,0.5,0.9,1])12345异常值 查看各个统计量 data.describe() 对某一列 col=data[3]col[np.abs(col)>3] 选出全部含有“超过3或-3的值的行 data[(np.abs(data)>3).any(1)] 异常值替换 data[np.abs(data)>3]=np.sign(data)*312345678910111213抽样 随机抽取k行 df.take(np.random.permutation(len(df))[:k]) 随机抽取k行,但是k可能大于df的行数 可以理解为过抽样了 df.take(np.random.randint(0,len(df),size=k))1234567数据摊平处理 相当于将类别属性转成因子类型,比如是否有车,这个字段有3个不同的值,有,没有,过段时间买,那么将会被编码成3个字段,有车,没车,过段时间买车,每个字段用0-1二值填充变成数值型。 对摊平的数据列增加前缀 dummies = pd.get_dummies(df['key'],prefix='key') 将摊平产生的数据列拼接回去 df[['data1']].join(dummies)12345字符串操作 拆分 strings.split(',') 根据正则表达式切分 re.split('s+',strings) 连接 'a'+'b'+'c'...或者'+'.join(series) 判断是否存在 's' in strings`strings.find('s') 计数 strings.count(',') 替换 strings.replace('old','new') 去除空白字符 s.strip()12345678910111213141516171819202122232425正则表达式 正则表达式需要先编译匹配模式,然后才去匹配查找,这样能节省大量的CPU时间。 re.complie:编译 findall:匹配所有 search:只返回第一个匹配项的起始和结束地址 match:值匹配字符串的首部 sub:匹配替换,如果找到就替换 原始字符串 strings = 'sdf@153.com,dste@qq.com,sor@gmail.com' 编译匹配模式,IGNORECASE可以在使用的时候对大小写不敏感 pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'regex = re.compile(pattern,flags=re.IGNORECASE) 匹配所有 regex.findall(strings) 使用search m = regex.search(strings) #获取匹配的地址strings[m.start():m.end()] 匹配替换 regex.sub('new_string', strings)12345678910111213141516根据模式再切分 将模式切分,也就是将匹配到的进一步切分,通过pattern中的括号实现. pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'regex = re.compile(pattern)regex.findall(strings) 如果使用match m=regex.match(string)m.groups() 效果是这样的 suzyu123@163.com --> [(suzyu123, 163, com)] 获取 list-tuple 其中的某一列 matches.get(i)12345678910111213分组聚合,计算 group_by技术 根据多个索引分组,然后计算均值 means = df['data1'].groupby([df['index1'],df['index2']).mean() 展开成透视表格式 means.unstack()12345分组后价将片段做成一个字典 pieces = dict(list(df.groupby('index1'))) pieces['b']123groupby默认是对列(axis=0)分组,也可以在行(axis=1)上分组 语法糖,groupby的快捷函数 df.groupby('index1')['col_names']df.groupby('index1')[['col_names']] 是下面代码的语法糖 df['col_names'].groupby(df['index1']) df.groupby(['index1','index2'])['col_names'].mean()1234567通过字典或series进行分组 people = DataFrame(np.random.randn(5, 5), columns=['a', 'b', 'c', 'd', 'e'], index=['Joe', 'Steve', 'Wes', 'Jim','Travis']) 选择部分设为na people.ix[2:3,['b','c']]=np.na mapping = {'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f' : 'orange'} people.groupby(mapping,axis=1).sum()1234567891011通过函数进行分组 根据索引的长度进行分组 people.groupby(len).sum()12数据聚合 使用自定义函数 对所有的数据列使用自定义函数 df.groupby('index1').agg(myfunc) 使用系统函数 df.groupby('index1')['data1']describe()12345根据列分组应用多个函数 分组 grouped = df.groupby(['col1','col2']) 选择多列,对每一列应用多个函数 grouped['data1','data2'...].agg(['mean','std','myfunc'])12345对不同列使用不同的函数 grouped = df.groupby(['col1','col2']) 传入一个字典,对不同的列使用不同的函数 不同的列可以应用不同数量的函数 grouped.agg({'data1':['min','max','mean','std'], 'data2':'sum'}) 123456分组计算后重命名列名 grouped = df.groupby(['col1','col2']) grouped.agg({'data1':[('min','max','mean','std'),('d_min','d_max','d_mean','d_std')], 'data2':'sum'}) 1234返回的聚合数据不要索引 df.groupby(['sex','smoker'], as_index=False).mean()1分组计算结果添加前缀 对计算后的列名添加前缀 df.groupby('index1').mean().add_prefix('mean_')12将分组计算后的值替换到原数据框 将函数应用到各分组,再将分组计算的结果代换原数据框的值 也可以使用自定义函数 df.groupby(['index1','index2'...]).transform(np.mean)123更一般化的apply函数 df.groupby(['col1','col2'...]).apply(myfunc) df.groupby(['col1','col2'...]).apply(['min','max','mean','std'])123禁用分组键 分组键会跟原始对象的索引共同构成结果对象中的层次化索引 df.groupby('smoker', group_keys=False).apply(mean)1分组索引转成df的列 某些情况下,groupby的as_index=False参数并没有什么用,得到的还是一个series,这种情况一般是尽管分组了,但是计算需要涉及几列,最后得到的还是series,series的index是层次化索引。这里将series转成dataframe,series的层次化索引转成dataframe的列。 def fmean(df): """需要用两列才能计算最后的结果""" skus=len(df['sku'].unique()) sums=df['salecount'].sum() return sums/skus 尽管禁用分组键,得到的还是series salemean=data.groupby(by=['season','syear','smonth'],as_index=False).apply(fmean) 将series转成dataframe,顺便设置索引 sub_df = pd.DataFrame(salemean.index.tolist(),columns=salemean.index.names,index=salemean.index) 将groupby的结果和sub_df合并 sub_df['salemean']=salemean12345678910111213桶分析与分位数 对数据切分段,然后对每一分段应用函数 frame = DataFrame({'col1':np.random.randn(1000), 'col2':np.random.randn(1000)}) 数据分段,创建分段用的因子 返回每一元素是属于哪一分割区间 factor = pd.cut(frame.col1, 4) 分组计算,然后转成数据框形式 grouped = frame.col2.groupby(factor)grouped.apply(myfunc).unstack()12345678910用分组的均值填充缺失值 自定义函数 fill_mean= lambda x:x.fillna(x.mean()) 分组填充 df.groupby(group_key).apply(fill_mean)12345分组后不同的数据替换不同的值 定义字典 fill_value = {'east':0.5, 'west':-1} 定义函数 fill_func = lambda x:x.fillna(fill_value(x.name)) 分组填充 df.groupby(['index1','index2'...]).apply(fill_func)12345678sql操作 有时候觉得pandas很方便,但是有时候却很麻烦,不如SQL方便。因此pandas中也有一些例子,用pandas实现SQL的功能,简单的就不说了,下面说些复杂点的操作。 之所以说这个复杂的语句,是因为不想将这些数据操作分写在不同的语句中,而是从头到尾连续编码实现一个功能。 SQL复杂操作用到的主要函数是assign,简单说其实和join的功能是一样的,根据df1,df2的索引值来将df2拼接到df1上。 两个函数是query,也听方便的。 有一批销量数据,筛选出那些有2个月以上的销量产品的数据,说白了就是剔除那些新上市产品的数据 方法是先统计每个产品的数据量,然后选出那些数据量>2的产品,再在数据表中选择这些产品 sku smonth a 1 a 2 a 3 a 4 b 5 b 6 b 7 b 8 c 9 c 10 按sku分组,统计smonth的次数,拼接到salecount中,然后查询cnt>2的 salecount.assign(cnt=salecount.groupby(['sku'])['smonth'].count()).query('cnt>2')
xuning715 2019-12-02 01:10:39 0 浏览量 回答数 0

回答

回2楼啊里新人的帖子 在日常的业务开发中,常见使用到索引的地方大概有两类: 第一类.做业务约束需求,比如需要保证表中每行的单个字段或者某几个组合字段是唯一的,则可以在表中创建唯一索引; 比如:需要保证test表中插入user_id字段的值不能出现重复,则在设计表的时候,就可以在表中user_id字段上创建一个唯一索引: CREATE TABLE `test` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `user_id` int(11) NOT NULL,   `gmt_create` datetime DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `uk_userid` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; 第二类.提高SQL语句执行速度,可以根据SQL语句的查询条件在表中创建合适的索引,以此来提升SQL语句的执行速度; 此过程好比是去图书找一本书,最慢的方法就是从图书馆的每一层楼每一个书架一本本的找过去;快捷一点的方法就是先通过图书检索来确认这一本书在几楼那个书架上,然后直接去找就可以了;当然创建这个索引也需要有一定的代价,需要存储空间来存放,需要在数据行插入,更新,删除的时候维护索引: 例如: CREATE TABLE `test_record` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `user_id` int(11) NOT NULL,   `gmt_create` datetime DEFAULT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5635996 DEFAULT CHARSET=utf8 该表有500w的记录,我需要查询20:00后插入的记录有多少条记录: mysql> select count(*) from test_record where gmt_create>'2014-12-17 20:00:00'; +----------+ | count(*) | +----------+ |        1 | +----------+ 1 row in set (1.31 sec) 可以看到查询耗费了1.31秒返回了1行记录,如果我们在gmt_create字段上添加索引: mysql> alter table test_record add index ind_gmt_create(gmt_create); Query OK, 0 rows affected (21.87 sec) Records: 0  Duplicates: 0  Warnings: 0 mysql> select count(*) from test_record where gmt_create>'2014-12-17 20:00:00'; +----------+ | count(*) | +----------+ |        1 | +----------+ 1 row in set (0.01 sec) 查询只消耗了0.01秒中就返回了记录. 总的来说,为SQL语句(select,update,delete)创建必要的索引是必须的,这样虽然有一定的性能和空间消耗,但是是值得,尤其是在大并发的请求下,大量的数据被扫描造成系统IO和CPU资源消耗完,进而导致整个数据库不可服务. ------------------------- 怎么学好数据库是一个比较大题目,数据库不仅仅是写SQL那么简单,即使知道了SQL怎么写,还需要很清楚的知道这条SQL他大概扫描了多少数据,返回多少数据,是否需要创建索引。至于SQL优化是一个比较专业的技术活,但是可以通过学习是可以掌握的,你可以把一条sql从执行不出来优化到瞬间完成执行,这个过程的成就感是信心满满的。学习的方法可以有以下一些过程:1、自己查资料,包括书本,在线文档,google,别人的总结等等,试图自己解决2、多做实验,证明自己的想法以及判断3、如果实在不行,再去论坛问,或者问朋友4、如果问题解决了,把该问题的整个解决方法记录下来,以备后来的需要5、多关注别人的问题,或许以后自己就遇到了,并总是试图去多帮助别人6、习惯从多个方面去考虑问题,并且养成良好的总结习惯 下面是一些国内顶级数据库专家学习数据库的经验分享给大家: http://www.eygle.com/archives/2005/08/ecinieoracleouo.html 其实学习任何东西都是一样,没有太多的捷径可走,必须打好了坚实的基础,才有可以在进一步学习中得到快速提高。王国维在他的《人间词话》中曾经概括了为学的三种境界,我在这里套用一下: 古今之成大事业、大学问者,罔不经过三种之境界。"昨夜西风凋碧树。独上高楼,望尽天涯路。"此第一境界也。"衣带渐宽终不悔,为伊消得人憔悴。"此第二境界也。"众里寻他千百度,蓦然回首,那人却在灯火阑珊处。"此第三境界也。 学习Oracle,这也是你必须经历的三种境界。 第一层境界是说,学习的路是漫漫的,你必须做好充分的思想准备,如果半途而废还不如不要开始。 这里,注意一个"尽"字,在开始学习的过程中,你必须充分阅读Oracle的基础文档,概念手册、管理手册、备份恢复手册等(这些你都可以在http://tahiti.oracle.com 上找到);OCP认证的教材也值得仔细阅读。打好基础之后你才具备了进一步提升的能力,万丈高楼都是由地而起。 第二层境界是说,尽管经历挫折、打击、灰心、沮丧,也都要坚持不放弃,具备了基础知识之后,你可以对自己感兴趣或者工作中遇到的问题进行深入的思考,由浅入深从来都不是轻而易举的,甚至很多时候你会感到自己停滞不前了,但是不要动摇,学习及理解上的突破也需要时间。 第三次境界是说,经历了那么多努力以后,你会发现,那苦苦思考的问题,那百思不得其解的算法原理,原来答案就在手边,你的思路豁然开朗,宛如拨云见月。这个时候,学习对你来说,不再是个难题,也许是种享受,也许成为艺术。 所以如果你想问我如何速成,那我是没有答案的。 不经一番寒彻骨,哪得梅花扑鼻香。 当然这三种境界在实际中也许是交叉的,在不断的学习中,不断有蓦然回首的收获。 我自己在学习的过程中,经常是采用"由点及面法"。 当遇到一个问题后,一定是深入下去,穷究根本,这样你会发现,一个简单的问题也必定会带起一大片的知识点,如果你能对很多问题进行深入思考和研究,那么在深处,你会发现,这些面逐渐接合,慢慢的延伸到oracle的所有层面,逐渐的你就能融会贯通。这时候,你会主动的去尝试全面学习Oracle,扫除你的知识盲点,学习已经成为一种需要。 由实践触发的学习才最有针对性,才更能让你深入的理解书本上的知识,正所谓:" 纸上得来终觉浅,绝知此事要躬行"。实践的经验于我们是至为宝贵的。 如果说有,那么这,就是我的捷径。 想想自己,经常是"每有所获,便欣然忘食", 兴趣才是我们最好的老师。 Oracle的优化是一门学问,也是一门艺术,理解透彻了,你会知道,优化不过是在各种条件之下做出的均衡与折中。 内存、外存;CPU、IO...对这一切你都需要有充分的认识和相当的了解,管理数据库所需要的知识并不单纯。 作为一个数据库管理人员,你需要做的就是能够根据自己的知识以及经验在各种复杂情况下做出快速正确的判断。当问题出现时,你需要知道使用怎样的手段发现问题的根本;找到问题之后,你需要运用你的知识找到解决问题的方法。 这当然并不容易,举重若轻还是举轻若重,取决于你具备怎样的基础以及经验积累。 在网络上,Howard J. Rogers最近创造了一个新词组:Voodoo Tuning,用以形容那些没有及时更新自己的知识技能的所谓的Oracle技术专家。由于知识的陈旧或者理解的肤浅,他们提供的很多调整建议是错误的、容易使人误解的,甚至是荒诞的。他们提供的某些建议在有些情况下也许是正确的,如果你愿意回到Oracle5版或者6版的年代;但是这些建议在Oracle7.0,8.0 或者 Oracle8i以后往往是完全错误的。 后来基于类似问题触发了互联网内Oracle顶级高手的一系列深入讨论,TOM、Jonathan Lewis、HJR等人都参与其中,在我的网站上(www.eygle.com )上对这些内容及相关链接作了简要介绍,有兴趣的可以参考。 HJR给我们提了很好的一个提示:对你所需要调整的内容,你必须具有充分的认识,否则你做出的判断就有可能是错误的。 这也是我想给自己和大家的一个建议: 学习和研究Oracle,严谨和认真必不可少。 当然 你还需要勤奋,我所熟悉的在Oracle领域有所成就的技术人员,他们共同的特点就是勤奋。 如果你觉得掌握的东西没有别人多,那么也许就是因为,你不如别人勤奋。 要是你觉得这一切过于复杂了,那我还有一句简单的话送给大家: 不积跬步,无以至千里。学习正是在逐渐积累过程中的提高。 现在Itpub给我们提供了很好的交流场所,很多问题都可以在这里找到答案,互相讨论,互相学习。这是我们的幸运,我也因此非常感谢这个网络时代。 参考书籍: 如果是一个新人可以先买一些基本的入门书籍,比如MySQL:《 深入浅出MySQL——数据库开发、优化与管理维护 》,在进阶一点的就是《 高性能MySQL(第3版) 》 oracle的参考书籍: http://www.eygle.com/archives/2006/08/oracle_fundbook_recommand.html 最后建议不要在数据库中使用外键,让应用程序来保证。 ------------------------- Re:回 9楼(千鸟) 的帖子 我有一个问题想问问,现在在做一个与图书有关的项目,其中有一个功能是按图书书名搜索相似图书列表,问题不难,但是想优化一下,有如下问题想请教一下: 1、在图书数据库数据表的书名字段里,按图书书名进行关键字搜索,如何快速搜索相关的图书?   现在由于数据不多,直接用的like模糊查找验证功能而已; 如果数据量不大,是可以在数据库中完成搜索的,可以在搜索字段上创建索引,然后进行搜索查询: CREATE TABLE `book` (   `book_id` int(11) NOT NULL AUTO_INCREMENT,   `book_name` varchar(100) NOT NULL,   .............................   PRIMARY KEY (`book_id`),   KEY `ind_name` (`book_name`) ) ENGINE=InnoDB select book.*  from book , (select book_id from book where book_name like '%算法%')  book_search_id  where book.book_id=book_search_id.book_id; 但是当数据量变得很大后,就不在适合了,可以采用一些其他的第三方搜索技术比如sphinx; 2、如何按匹配的关键度进行快速排序?比如搜索“算法”,有一本书是《算法》,另一本书是《算法设计》,要求前者排在更前面。 现在的排序是根据数据表中的主键序号id进行的排序,没有达到想要的效果。 root@127.0.0.1 : test 15:57:12> select book_id,book_name from book_search where book_name like '%算%' order by book_name; +---------+--------------+ | book_id | book_name    | +---------+--------------+ |       2 | 算法       | |       1 | 算法设计 | ------------------------- 回 10楼(大黑豆) 的帖子 模糊查询分为半模糊和全模糊,也就是: select * from book where name like 'xxx%';(半模糊) select * from book where name like '%xxx%';(全模糊) 半模糊可以可以使用到索引,全模糊在上面场景是不能使用到索引的,但可以进行一些改进,比如: select book.*  from book , (select book_id from book where book_name like '%算法%')  book_search_id   where book.book_id=book_search_id.book_id; 注意这里book_id是主键,同时在book_name上创建了索引 上面的sql语句可以利用全索引扫描来完成优化,但是性能不会太好;特别在数据量大,请求频繁的业务场景下不要在数据库进行模糊查询; 非得使用数据库的话 ,建议不要在生产库进行查询,可以在只读节点进行查询,避免查询造成主业务数据库的资源消耗完,导致故障. 可以使用一些开源的搜索引擎技术,比如sphinx. ------------------------- 回 11楼(蓝色之鹰) 的帖子 我想问下,sql优化一般从那几个方面入手?多表之间的连接方式:Nested Loops,Hash Join 和 Sort Merge Join,是不是Hash Join最优连接? SQL优化需要了解优化器原理,索引的原理,表的存储结构,执行计划等,可以买一本书来系统的进行学习,多多实验; 不同的数据库优化器的模型不一样,比如oracle支持NL,HJ,SMJ,但是mysql只支持NL,不通的连接方式适用于不同的应用场景; NL:对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择 HJ:对于列连接是做大数据集连接时的常用方式 SMJ:通常情况下散列连接的效果都比排序合并连接要好,然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序合并连接的性能会优于散列连接 ------------------------- Re:回 19楼(原远) 的帖子 有个问题:分类表TQueCategory,问题表TQuestion(T-SQL) CREATE TABLE TQueCategory ( ID INT IDENTITY(1,1) PRIMARY KEY,        --问题分类ID NAME VARCHAR(20)        --问题分类名称 ) CREATE TABLE TQuestion ( ID INT IDENTITY(1,1) PRIMARY KEY,        --问题ID CateID INT NOT NULL,        --问题分类ID TITLE VARCHAR(50),        --问题标题 CONTENT VARCHAR(500)        --问题内容 ) 当前要统计某个分类下的问题数,有两种方式: 1.每次统计,在TQuestion通过CateID进行分组统计 SELECT CateID,COUNT(1) AS QueNum FROM TQuestion GROUP BY CateID WHERE 1=1 2.在TQueCategory表增加字段QueNum,用于标识该分类下的问题数量 ALTER TABLE TQueCategory ADD QueNum INT SELECT CateID,QueNum FROM TQueCategory 问:在哪种业务应用场景下采用上面哪种方式性能比较好,为什么? ############################################################################################### 方案 一 需要对 TQuestion 的 CateID字段 进行分组 ,可以在 CateID上创建一个索引,这样就可以索引扫描来完成查询; 方案 二 需要对 TQueCategory 进行扫描就可以得出结果,但是必须在问题表有插入,删除的时候维护quenum数量; 单单从SQL的性能来看, 分类表的数量应该是远远小于问题表的数量的,所以方案二的性能会比较好; 但是如果 TQuestion 的插入非常频繁的话,会带来对 TQueCategory的频繁更新,一次 TQuestion 的 insert或deleted就会带来一次 TQueCategory 的update,这个代价其实是蛮高的; 如果这个分类统计的查询不是非常频繁的话,建议还是使用方案一; 同时还可能还会其他的业务逻辑统计需求(例如: CateID +时间),这个时候在把逻辑放到 TQueCategory就不合适了。 ------------------------- 回 20楼(原远) 的帖子 经验之谈,仅供参考 使用外键在开发上确实省去了很多功夫,但是把业务逻辑交由数据库来完成,对后期的维护来说是很麻烦的事情,不利于维护. ------------------------- 回 21楼(玩站网) 的帖子 无关技术方面: 咨询一下,现在mysql新的版本,5.5.45后貌似修改了开源协议。 是否意味着今后我们商业化使用mysql将受到限制? 如果甲骨文真周到那一步,rds是否会受到影响? 一个疑惑: 为什么很少见到有人用mysql正则匹配?性能不好还是什么原因? ######################################## MySQL有商业版 和 社区版,RDS的MySQL采用开源的社区版进行改进,由专门的RDS MySQL源码团队来维护,国内TOP 10的mysql源码贡献者大部分都在RDS,包括了@丁奇 ,@彭立勋 ,@印风 等; 不在数据库中做业务计算,是保证数据库运行稳定的一个好的设计经验; 是否影响性能与你的sql的执行频率,需要参与的计算数据量相关,当然了还包括数据库所在主机的IO,cpu,内存等资源,离开了这些谈性能是没有多大意义的; ------------------------- 回 22楼(比哥) 的帖子 分页该怎么优化才行??? ######################### 可以参考这个链接,里面有很多的最佳实践,其中就包括了分页语句的优化: http://bbs.aliyun.com/read/168647.html?spm=5176.7114037.1996646101.1.celwA1&pos=1 普通写法: select  *  from t where sellerid=100 limit 100000,20 普通limit M,N的翻页写法,往往在越往后翻页的过程中速度越慢,原因 mysql会读取表中的前M+N条数据,M越大,性能就越差: 优化写法: select t1.* from  t t1,             (select id from t  sellerid=100 limit 100000,20) t2 where t1.id=t2.id; 优化后的翻页写法,先查询翻页中需要的N条数据的主键id,在根据主键id 回表查询所需要的N条数据,此过程中查询N条数据的主键ID在索引中完成 注意:需要在t表的sellerid字段上创建索引 create index ind_sellerid on t(sellerid); 案例: user_A (21:42:31): 这个sql该怎么优化,执行非常的慢: | Query   |   51 | Sending data | select id, ... from t_buyer where sellerId = 765922982 and gmt_modified >= '1970-01-01 08:00:00' and gmt_modified <= '2013-06-05 17:11:31' limit 255000, 5000 SQL改写:selectt2.* from (selectid from t_buyer where sellerId = 765922982   andgmt_modified >= '1970-01-01 08:00:00'   andgmt_modified <= '2013-06-05 17:11:31' limit255000, 5000)t1,t_buyer t2 where t1.id=t2.id index:seller_id,gmt_modified user_A(21:58:43): 好像很快啊。神奇,这个原理是啥啊。牛!!! user_A(21:59:55): 5000 rows in set (4.25 sec), 前面要90秒。 ------------------------- 回 27楼(板砖大叔) 的帖子 这里所说的索引都是普通的b-tree索引,mysql,sqlserver,oracle 的关系数据库都是默认支持的; ------------------------- 回 32楼(veeeye) 的帖子 可以详细说明一下“最后建议不要在数据库中使用外键,让应用程序来保证。 ”的原因吗?我们公司在项目中经常使用外键,用程序来保证不是相对而言更加复杂了吗? 这里的不建议使用外键,主要考虑到 : 第一.维护成本上,把一些业务逻辑交由数据库来保证,当业务需求发生改动的时候,需要同时考虑应用程序和数据库,有时候一些数据库变更或者bug,可能会导致外键的失效;同时也给数据库的管理人员带来维护的麻烦,不便于管理。 第二.性能上考虑,当大量数据写入的时候,外键肯定会带来一定的性能损耗,当出现这样的问题时候,再来改造去除外键,真的就不值得了; 最后,不在数据库中参与业务的计算(存储过程,函数,触发器,外键),是保证数据库运行稳定的一个好的最佳实践。 ------------------------- 回 33楼(优雅的固执) 的帖子 ReDBA专家门诊一期:索引与sql优化 十分想请大师分享下建立索引的经验 我平时简历索引是这样的 比如订单信息的话 建立 订单号  唯一聚集索引 其他的比如   客户编号 供应商编号 商品编号 这些建立非聚集不唯一索引   ################################################## 建立索引,需要根据你的SQL语句来进行创建,不是每一个字段都需要进行创建,也不是一个索引都不创建,,可以把你的SQL语句,应用场景发出来看看。 索引的创建确实是一个非常专业的技术活,需要掌握:表的存储方式,索引的原理,数据库的优化器,统计信息,最后还需要能够读懂数据库的执行计划,以此来判断索引是否创建正确; 所以需要进行系统的学习才能掌握,附件是我在2011年的时候的一次公开课的ppt,希望对你有帮助,同时可以把你平时遇到的索引创建的疑惑发到论坛上来,大家可以一起交流。 ------------------------- 回 30楼(几几届) 的帖子 我也是这样,简单的会,仔细写也会写出来,但是就是不知道有没有更快或者更好的 #################################################### 多写写SQL,掌握SQL优化的方法,自然这些问题不在话下了。 ------------------------- 回 40楼(小林阿小林) 的帖子 mysql如何查询需要优化的语句,比如慢查询的步奏,如何找出需要通知程序员修改或者优化的sql语句 ############################################################ 可以将mysql的慢日志打开,就可以记录执行时间超过指定阀值的慢SQL到本地文件或者数据库的slow_log表中; 在RDS中默认是打开了慢日志功能的:long_query_time=1,表示会记录执行时间>=1秒的慢sql; 如何快速找到mysql瓶颈: 简单一点的方法,可以通过监控mysql所在主机的性能(CPU,IO,load等)以及mysql本身的一些状态值(connections,thread running,qps,命中率等); RDS提供了完善的数据库监控体系,包括了CPU,IOPS,Disk,Connections,QPS,可以重点关注cpu,IO,connections,disk 4个 指标; cpu,io,connections主要体现在了性能瓶颈,disk主要体现了空间瓶颈; 有时候一条慢sql语句的频繁调用,也可能导致整个实例的cpu,io,connections达到100%;也有可能一条排序的sql语句,消耗大量的临时空间,导致实例的空间消耗完。 ------------------------- 下面是分析一个cpu 100%的案例分析:该实例的cpu已经到达100% 查看当前数据库的活动会话信息:当前数据库有较多的活跃线程在数据库中执行查看当前数据库正在执行的sql: 可以看到这条sql执行的非常缓慢:[tr=rgb(100, 204, 255)]delete from task_process where task_id='1801099' 查看这个表的索引: CREATE TABLE `task_process` (  `id` int(11) NOT NULL AUTO_INCREMENT,    ................  `task_id` int(11) NOT NULL DEFAULT '0' COMMENT '??????id',   ................  PRIMARY KEY (`id`),  KEY `index_over_task` (`is_over`,`task_id`),  KEY `index_over` (`is_over`,`is_auto`) USING BTREE,  KEY `index_process_sn` (`process_sn`,`is_over`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=32129710; 可以看到这个表有3KW的数据,但是没有task_id字段开头的索引,导致该sql语句删除需要进行全表扫描: 在我们的诊断报告中已经将该sql语句捕获到,同时给你提出该怎样进行索引的添加。 广告:诊断报告将会在1月底发布到控制台,到时候用户可以直接查看诊断建议,来完成你的数据库优化。 ------------------------- 回 45楼(dentrite) 的帖子 datetime和int都是占用数据库4个字节,所以在空间上没有什么差别;但是为了可读性,建议还是使用datetime数据类型。 ------------------------- 回 48楼(yuantel) 的帖子 麻烦把ecs_brand和ecs_goods的表结构发出来一下看看 。 ------------------------- 回 51楼(小林阿小林) 的帖子 普通的 ECS服务器上目前还没有这样的慢SQL索引建议的工具。 不过后续有IDBCloud将会集成这样的sql诊断功能,使用他来管理ECS上的数据库就可以使用这样的功能了 。
玄惭 2019-12-02 01:16:11 0 浏览量 回答数 0

回答

参考:https://www.iteblog.com/archives/2530.html分布式和去中心化(Distributed and Decentralized)Cassandra 是分布式的,这意味着它可以运行在多台机器上,并呈现给用户一个一致的整体。事实上,在一个节点上运行 Cassandra 是没啥用的,虽然我们可以这么做,并且这可以帮助我们了解它的工作机制,但是你很快就会意识到,需要多个节点才能真正了解 Cassandra 的强大之处。它的很多设计和实现让系统不仅可以在多个节点上运行,更为多机架部署进行了优化,甚至一个 Cassandra 集群可以运行在分散于世界各地的数据中心上。你可以放心地将数据写到集群的任意一台机器上,Cassandra 都会收到数据。对于很多存储系统(比如 MySQL, Bigtable),一旦你开始扩展它,就需要把某些节点设为主节点,其他则作为从节点。但 Cassandra 是无中心的,也就是说每个节点都是一样的。与主从结构相反,Cassandra 的协议是 P2P 的,并使用 gossip 来维护存活或死亡节点的列表。关于 gossip 可以参见《分布式原理:一文了解 Gossip 协议》。去中心化这一事实意味着 Cassandra 不会存在单点失效。Cassandra 集群中的所有节点的功能都完全一样, 所以不存在一个特殊的主机作为主节点来承担协调任务。有时这被叫做服务器对称(server symmetry)。综上所述,Cassandra 是分布式、无中心的,它不会有单点失效,所以支持高可用性。弹性可扩展(Elastic Scalability)可扩展性是指系统架构可以让系统提供更多的服务而不降低使用性能的特性。仅仅通过给现有的机器增加硬件的容量、内存进行垂直扩展,是最简单的达到可扩展性的手段。而水平扩展则需要增加更多机器,每台机器提供全部或部分数据,这样所有主机都不必负担全部业务请求。但软件自己需要有内部机制来保证集群中节点间的数据同步。弹性可扩展是指水平扩展的特性,意即你的集群可以不间断的情况下,方便扩展或缩减服务的规模。这样,你就不需要重新启动进程,不必修改应用的查询,也无需自己手工重新均衡数据分布。在 Cassandra 里,你只要加入新的计算机,Cassandra 就会自动地发现它并让它开始工作。高可用和容错(High Availability and Fault Tolerance)从一般架构的角度来看,系统的可用性是由满足请求的能力来量度的。但计算机可能会有各种各样的故障,从硬件器件故障到网络中断都有可能。如何计算机都可能发生这些情况,所以它们一般都有硬件冗余,并在发生故障事件的情况下会自动响应并进行热切换。对一个需要高可用的系统,它必须由多台联网的计算机构成,并且运行于其上的软件也必须能够在集群条件下工作,有设备能够识别节点故障,并将发生故障的中端的功能在剩余系统上进行恢复。Cassandra 就是高可用的。你可以在不中断系统的情况下替换故障节点,还可以把数据分布到多个数据中心里,从而提供更好的本地访问性能,并且在某一数据中心发生火灾、洪水等不可抗灾难的时候防止系统彻底瘫痪。可调节的一致性(Tuneable Consistency)2000年,加州大学伯克利分校的 Eric Brewer 在 ACM 分布式计算原理会议提出了著名的 CAP 定律。CAP 定律表明,对于任意给定的系统,只能在一致性(Consistency)、可用性(Availability)以及分区容错性(Partition Tolerance)之间选择两个。关于 CAP 定律的详细介绍可参见《分布式系统一致性问题、CAP定律以及 BASE 理论》以及《一篇文章搞清楚什么是分布式系统 CAP 定理》。所以 Cassandra 在设计的时候也不得不考虑这些问题,因为分区容错性这个是每个分布式系统必须考虑的,所以只能在一致性和可用性之间做选择,而 Cassandra 的应用场景更多的是为了满足可用性,所以我们只能牺牲一致性了。但是根据 BASE 理论,我们其实可以通过牺牲强一致性获得可用性。Cassandra 提供了可调节的一致性,允许我们选定需要的一致性水平与可用性水平,在二者间找到平衡点。因为客户端可以控制在更新到达多少个副本之前,必须阻塞系统。这是通过设置副本因子(replication factor)来调节与之相对的一致性级别。通过副本因子(replication factor),你可以决定准备牺牲多少性能来换取一致性。 副本因子是你要求更新在集群中传播到的节点数(注意,更新包括所有增加、删除和更新操作)。客户端每次操作还必须设置一个一致性级别(consistency level)参数,这个参数决定了多少个副本写入成功才可以认定写操作是成功的,或者读取过程中读到多少个副本正确就可以认定是读成功的。这里 Cassandra 把决定一致性程度的权利留给了客户自己。所以,如果需要的话,你可以设定一致性级别和副本因子相等,从而达到一个较高的一致性水平,不过这样就必须付出同步阻塞操作的代价,只有所有节点都被更新完成才能成功返回一次更新。而实际上,Cassandra 一般都不会这么来用,原因显而易见(这样就丧失了可用性目标,影响性能,而且这不是你选择 Cassandra 的初衷)。而如果一个客户端设置一致性级别低于副本因子的话,即使有节点宕机了,仍然可以写成功。总体来说,Cassandra 更倾向于 CP,虽然它也可以通过调节一致性水平达到 AP;但是不推荐你这么设置。面向行(Row-Oriented)Cassandra 经常被看做是一种面向列(Column-Oriented)的数据库,这也并不算错。它的数据结构不是关系型的,而是一个多维稀疏哈希表。稀疏(Sparse)意味着任何一行都可能会有一列或者几列,但每行都不一定(像关系模型那样)和其他行有一样的列。每行都有一个唯一的键值,用于进行数据访问。所以,更确切地说,应该把 Cassandra 看做是一个有索引的、面向行的存储系统。Cassandra 的数据存储结构基本可以看做是一个多维哈希表。这意味着你不必事先精确地决定你的具体数据结构或是你的记录应该包含哪些具体字段。这特别适合处于草创阶段,还在不断增加或修改服务特性的应用。而且也特别适合应用在敏捷开发项目中,不必进行长达数月的预先分析。对于使用 Cassandra 的应用,如果业务发生变化了,只需要在运行中增加或删除某些字段就行了,不会造成服务中断。当然, 这不是说你不需要考虑数据。相反,Cassandra 需要你换个角度看数据。在 RDBMS 里, 你得首先设计一个完整的数据模型, 然后考虑查询方式, 而在 Cassandra 里,你可以首先思考如何查询数据,然后提供这些数据就可以了。灵活的模式(Flexible Schema)Cassandra 的早期版本支持无模式(schema-free)数据模型,可以动态定义新的列。 无模式数据库(如 Bigtable 和 MongoDB)在访问大量数据时具有高度可扩展性和高性能的优势。 无模式数据库的主要缺点是难以确定数据的含义和格式,这限制了执行复杂查询的能力。为了解决这些问题,Cassandra 引入了 Cassandra Query Language(CQL),它提供了一种通过类似于结构化查询语言(SQL)的语法来定义模式。 最初,CQL 是作为 Cassandra 的另一个接口,并且基于 Apache Thrift 项目提供无模式的接口。 在这个过渡阶段,术语“模式可选”(Schema-optional)用于描述数据模型,我们可以使用 CQL 的模式来定义。并且可以通过 Thrift API 实现动态扩展以此添加新的列。 在此期间,基础数据存储模型是基于 Bigtable 的。从 3.0 版本开始,不推荐使用基于 Thrift API 的动态列创建的 API,并且 Cassandra 底层存储已经重新实现了,以更紧密地与 CQL 保持一致。 Cassandra 并没有完全限制动态扩展架构的能力,但它的工作方式却截然不同。 CQL 集合(比如 list、set、尤其是 map)提供了在无结构化的格式里面添加内容的能力,从而能扩展现有的模式。CQL 还提供了改变列的类型的能力,以支持 JSON 格式的文本的存储。因此,描述 Cassandra 当前状态的最佳方式可能是它支持灵活的模式。高性能(High Performance)Cassandra 在设计之初就特别考虑了要充分利用多处理器和多核计算机的性能,并考虑在分布于多个数据中心的大量这类服务器上运行。它可以一致而且无缝地扩展到数百台机器,存储数 TB 的数据。Cassandra 已经显示出了高负载下的良好表现,在一个非常普通的工作站上,Cassandra 也可以提供非常高的写吞吐量。而如果你增加更多的服务器,你还可以继续保持 Cassandra 所有的特性而无需牺牲性能。
封神 2019-12-02 02:00:50 0 浏览量 回答数 0

问题

百问百答 《Java开发手册(嵩山版)》

从java命名标准来讲,代码中的命名需要注意什么? java中类名命名是用什么规则,有什么情形是例外的? POJO类中的布尔类型变量要不要加is前缀,为什么ÿ...
不语奈何 2021-03-25 13:30:32 28 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务 阿里云AIoT