blogjava-凯发k8网页登录

blogjava-凯发k8网页登录http://www.blogjava.net/qileilove/category/49945.html不想做屌丝的码农,不是好项目经理!屌丝生涯从此开始!zh-cnthu, 11 dec 2014 16:24:07 gmtthu, 11 dec 2014 16:24:07 gmt60mysql数字辅助表http://www.blogjava.net/qileilove/archive/2014/12/11/421322.html顺其自然evo顺其自然evothu, 11 dec 2014 15:43:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/11/421322.htmlhttp://www.blogjava.net/qileilove/comments/421322.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/11/421322.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421322.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421322.html最近在做一个活动签到的功能,每个用户每天签到,累计到一定次数,可以换一些奖品。
  签到表的设计如下
  create table `award_chance_history` (
  `id` int(11) not null auto_increment,
  `awardactid` int(11) default null comment '活动id',
  `vvid` bigint(20) default null comment '用户id',
  `createtime` timestamp not null default current_timestamp on update current_timestamp comment '签到时间',
  `reason` varchar(40) default null comment '事由',
  `additionalchance` int(11) default '0' comment '积分变动',
  `type` int(11) default null comment '类型',
  `chance_bak` int(11) default '0',
  primary key (`id`)
  ) engine=innodb auto_increment=1 default charset=utf8;
  到了的阶段,问题来了。
  测试需要让我做一批数据,模拟用户签到了20天,30天..以便测试.
  这在都不是事儿,用connect by直接可以解决.
  但是没有这个功能,
  一开始,我是这么做的
  这种场景其实可以用数字辅助表的方式,在mysql技术内幕()中有记录
  首先,创建数字辅助表
create table nums(id int not null primary key);
delimiter $$
create procedure pcreatenums(cnt int)
begin
declare s int default 1;
truncate table nums;
while s<=cnt do
insert into nums select s;
set s=s 1;
end while;
end $$
delimiter ;
delimiter $$
create procedure pfastcreatenums(cnt int)
begin
declare s int default 1;
truncate table nums;
insert into nums select s;
while s*2<=cnt do
insert into nums select id s from nums;
set s=s*2;
end while;
end $$
delimiter ;
  初始化数据
  call pfastcreatenums(10000);
  创建测试数据
  insert into award_chance_history(awardactid,vvid,reason,additionalchance,type,createtime)
  select 12,70021346,'手机签到测试',10,2,date_add('2014-12-14',interval id day) from nums order by id limit 10;
  这样就创建了从 2014-12-15以后的连续10天签到数据.


顺其自然evo 2014-12-11 23:43
]]>
plsql developer鲜为人知的快捷键http://www.blogjava.net/qileilove/archive/2014/12/11/421320.html顺其自然evo顺其自然evothu, 11 dec 2014 15:40:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/11/421320.htmlhttp://www.blogjava.net/qileilove/comments/421320.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/11/421320.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421320.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421320.html注释:
  使用plsql developer的朋友们是否有遇到如下情况
  ① 不小心关闭了有用的窗口;
  ② 有意义的前几分钟不用了且关闭的情况;
  ③ plsql developer界面中其中1个session 死掉了不得不关闭时,再重新开启点击恢复会话后可能不会和之前场景一摸一摸时;
  如上的情况都可以通过如下快捷键进行恢复.
  ctrl e【default】  ==> edit / recall statement
  显示结果:
  选中任意一行 双击 直接进入源编辑界面.
  更改该快捷键步骤:
  plsql developer --> tools --> preferences --> key configuration


顺其自然evo 2014-12-11 23:40
]]>
淘宝分布式配置管理服务diamondhttp://www.blogjava.net/qileilove/archive/2014/12/11/421319.html顺其自然evo顺其自然evothu, 11 dec 2014 15:39:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/11/421319.htmlhttp://www.blogjava.net/qileilove/comments/421319.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/11/421319.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421319.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421319.html 在一个环境中,同类型的服务往往会部署很多实例。这些实例使用了一些配置,为了更好地维护这些配置就产生了服务。通过这个服务可以轻松地管理这些应用服务的配置问题。应用场景可概括为:
  zookeeper的一种应用就是分布式配置管理(基于zookeeper的配置信息存储方案的设计与实现)。也有类似的实现:disconf。
  diamond则是淘宝开源的一种分布式配置管理服务的实现。diamond本质上是一个java写的web应用,其对外提供接口都是基于http协议的,在阅读代码时可以从实现各个接口的controller入手。
  分布式配置管理
  分布式配置管理的本质基本上就是一种推送-订阅模式的运用。配置的应用方是订阅者,配置管理服务则是推送方。概括为下图:
  其中,客户端包括管理人员publish数据到配置管理服务,可以理解为添加/更新数据;配置管理服务notify数据到订阅者,可以理解为推送。
  配置管理服务往往会封装一个客户端库,应用方则是基于该库与配置管理服务进行交互。在实际实现时,客户端库可能是主动拉取(pull)数据,但对于应用方而言,一般是一种事件通知方式。
  diamond中的数据是简单的key-value结构。应用方订阅数据则是基于key来订阅,未订阅的数据当然不会被推送。数据从类型上又划分为聚合和非聚合。因为数据推送者可能很多,在整个分布式环境中,可能有多个推送者在推送相同key的数据,这些数据如果是聚合的,那么所有这些推送者推送的数据会被合并在一起;反之如果是非聚合的,则会出现覆盖。
  数据的来源可能是人工通过管理端录入,也可能是其他服务通过配置管理服务的推送接口自动录入。
  架构及实现
  diamond服务是一个集群,是一个去除了单点的协作集群。如图:
  每一个角色出问题时,都可以尽量保证客户端对应用层提供服务。
  图中可分为以下部分讲解:


顺其自然evo 2014-12-11 23:39
]]>
ios开发之fmdbhttp://www.blogjava.net/qileilove/archive/2014/12/08/421196.html顺其自然evo顺其自然evomon, 08 dec 2014 14:00:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/08/421196.htmlhttp://www.blogjava.net/qileilove/comments/421196.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/08/421196.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421196.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421196.html  sqlite作为一个轻量级的,由于它占用的内存很少,因此在很多的嵌入式设备中得到广泛的使用。ios的sdk很早就开始支持了sqlite,我们只需要加入 libsqlite3.dylib 以及引入 sqlite3.h 头文件即可,但由于原生sqlite的api不是很友好,因此使用的话一般会对其做一层封装,其中以开源的fmdb最为流行。
  fmdb主要的类
  1.fmdatabase – 表示一个单独的sqlite数据库。 用来执行sqlite的命令。
  2.fmresultset – 表示fmdatabase执行查询后结果集
  3.fmdatabasequeue – 当你在多线程中执行操作,使用该类能确保线程安全。
  fmdb的使用
  数据库的创建:
  创建fmdatabase对象时需要参数为sqlite数据库文件路径。该路径可以是以下三种之一:
  1..文件路径。该文件路径无需真实存,如果不存在会自动创建。
  2..空字符串(@”")。表示会在临时目录创建一个临时数据库,当fmdatabase 链接关闭时,文件也被删除。
  3.null. 将创建一个内存数据库。同样的,当fmdatabase连接关闭时,数据会被销毁。
  内存数据库:
  通常数据库是存放在磁盘当中的。然而我们也可以让存放在内存当中的数据库,内存数据库的优点是对其操作的速度较快,毕竟访问内存的耗时低于访问磁盘,但内存数据库有如下缺陷:由于内存数据库没有被持久化,当该数据库被关闭后就会立刻消失,断电或程序崩溃都会导致数据丢失;不支持读写互斥处理,需要自己手动添加锁;无法被别的进程访问。
  临时数据库:
  临时数据库和内存数据库非常相似,两个数据库连接创建的临时数据库也是各自独立的,在连接关闭后,临时数据库将自动消失,其底层文件也将被自动删除。尽管磁盘文件被创建用于存储临时数据库中的数据信息,但是实际上临时数据库也会和内存数据库一样通常驻留在内存中,唯一不同的是,当临时数据库中数据量过大时,sqlite为了保证有更多的内存可用于其它操作,因此会将临时数据库中的部分数据写到磁盘文件中,而内存数据库则始终会将数据存放在内存中。
  创建数据库:fmdatabase *db= [fmdatabase databasewithpath:dbpath] ;
  在进行数据库的操作之前,必须要先把数据库打开,如果资源或权限不足无法打开或创建数据库,都会导致打开失败。
  如下为创建和打开数据库的示例:
  nsarray *paths = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes);
  nsstring *documentdirectory = [paths objectatindex:0];
  //dbpath: 数据库路径,存放在document中。
  nsstring *dbpath = [documentdirectory stringbyappendingpathcomponent:@"mytest.db"];
  //创建数据库实例 db  这里说明下:如果路径中不存在"mytest.db"的文件,sqlite会自动创建"mytest.db"
  fmdatabase *db= [fmdatabase databasewithpath:dbpath] ;
  if (![db open]) {
  nslog(@"could not open db.");
  return ;
  }
  更新操作
  一切不是select命令都视为更新操作,包括create, update, insert,alter,commit, begin, detach, delete, drop, end, explain, vacuum和replace等。
  创建表:
  [db executeupdate:@"create table mytable (name text,age integer)"];
  插入
  [db executeupdate:@"insert into mytable (name,age) values (?,?)",@"jason",[nsnumber numberwithint:20]];
  更新
  [db executeupdate:@"update mytable set name = ? where name = ? ",@"john",@"jason"];.
  删除
  [db executeupdate:@"delete from mytable where name = ?",@"jason"];
  查询操作
  select命令就是查询,执行查询的方法是以 -excutequery开头的。执行查询时,如果成功返回fmresultset对象, 错误返回nil. 读取信息的时候需要用while循环:
  fmresultset *s = [db executequery:@"select * from mytable"];
  while ([s next]) {
  //从每条记录中提取信息
  }
  关闭数据库
  当使用完数据库,你应该 -close 来关闭数据库连接来释放sqlite使用的资源。
  [db close];
  参数
  通常情况下,你可以按照标准的语句,用?表示执行语句的参数,如:
  insert into mytable values (?, ?, ?)
  然后,可以我们可以调用executeupdate方法来将?所指代的具体参数传入,通常是用变长参数来传递进去的,如下:
  nsstring *sql = @"insert into mytable (name, password) values (?, ?)";
  [db executeupdate:sql, user.name, user.password];
  这里需要注意的是,参数必须是nsobject的子类,所以象int,double,bool这种基本类型,需要进行相应的封装
  [db executeupdate:@"insert into mytable values (?)", [nsnumber numberwithint:42]];

多线程操作
  由于fmdatabase对象本身不是线程安全的,因此为了避免在多线程操作的时候出错,需要使用 fmdatabasequeue来执行相关操作。只需要利用一个数据库文件地址来初使化fmdatabasequeue,然后传入一个block到indatabase中,即使是多个线程同时操作,该queue也会确保这些操作能按序进行,保证线程安全。
  创建队列:
  fmdatabasequeue *queue = [fmdatabasequeue databasequeuewithpath:apath];
  使用方法:
[queue indatabase:^(fmdatabase *db) {
[db executeupdate:@"insert into mytable values (?)", [nsnumber numberwithint:1]];
[db executeupdate:@"insert into mytable values (?)", [nsnumber numberwithint:2]];
fmresultset *rs = [db executequery:@"select * from foo"];
while([rs next]) {
}
}];
  至于事务可以像这样处理:
[queue intransaction:^(fmdatabase *db, bool *rollback) {
[db executeupdate:@"insert into mytable values (?)", [nsnumber numberwithint:1]];
[db executeupdate:@"insert into mytable values (?)", [nsnumber numberwithint:2]];
[db executeupdate:@"insert into mytable values (?)", [nsnumber numberwithint:3]];
if (somethingwronghappened) {
*rollback = yes;
return;
}
// etc…
[db executeupdate:@"insert into mytable values (?)", [nsnumber numberwithint:4]];
}];


顺其自然evo 2014-12-08 22:00
]]>
alwayson可用性组功能测试(2)-sql server群集故障转移http://www.blogjava.net/qileilove/archive/2014/12/08/421179.html顺其自然evo顺其自然evomon, 08 dec 2014 12:38:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/08/421179.htmlhttp://www.blogjava.net/qileilove/comments/421179.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/08/421179.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421179.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421179.html三、  server群集故障转移对alwayson可用性组的影响
  1. 主副本在sql server群集clustest03/clustest03上
  1.1将节点转移server02.以下是故障转移界面。
  1.2 服务脱机,alwayson自然脱机,但侦听ip并没有脱机。
  1.3 sql服务联机后,侦听ip【10.0.0.224】会脱机重启,alwayson资源组联机
  2. 主副本在server03的服务上
  2.1 当前主副本在server03上,sql server故障转移对可用性组没有影响。以下转移脱机界面。
  测试总结
  a、 若主副本在sql 群集上,当服务脱机时候,侦听ip并不会脱机,alwayson会脱机;可用组不可用。
  b、 当服务重新联机,侦听ip会脱机重新联机,侦听ip会发生顺断。
  c、 重新联机到alwayson连接过程使用20秒左右。
  d、 当主副本不在sql群集上,群集的故障转移对可用性组没有影响。
相关文章






顺其自然evo 2014-12-08 20:38
]]>
sql server 2008 (r2) 单机版安装的先决条件http://www.blogjava.net/qileilove/archive/2014/12/05/421083.html顺其自然evo顺其自然evofri, 05 dec 2014 04:19:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/05/421083.htmlhttp://www.blogjava.net/qileilove/comments/421083.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/05/421083.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421083.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421083.html  在为客户提供凯发k8网页登录的技术支持时,发现安装 server 2008 (r2) 单机版出现的问题很多源于以下几个典型情况,而客户们有所不知,这正是sql server 安装所必须的先决条件:
  1.       .net framework 3.5 sp1
  2.        installer 4.5
  3.       visual studio 2008 sp1
  4.       在控制面板中设置区域和语言
  5.       小型企业安装sql server 2008 (r2) 标准版需要设置域
  6.       在windows server 2008 r2或windows 7中安装sql server 2008采用sp1整合安装模式
  1.     .net framework 3.5 sp1
  在 windows server 2008 r2中,你应该以添加windows功能的方法来安装.net  framework 3.5 sp1,而不是以一个独立的组件来进行安装。
  在其他版本的系统中,你只需点击安装文件setup.exe,其将自动安装.net framework 3.5 sp1 和 windows installer 4.5。
  运行sql server 2008 需要有 .net framework 3.5 sp1 (特别是 express 和 ia64版本) 和windows installer 4.5。在.net framework 和 windows installer 升级后,你需要重新启动使其生效。如果没有重启系统而再次尝试安装,则会跳出警告要求重启,您将选择使.net framework 和 windows installer生效或退出安装。
  如果你选择了取消,安装程序会报一个缺少安装windows installer 4.5 的错误。安装向导将 .net framework 和windows installer 的安装捆绑在一起,因此这两个组件会同时安装。一旦必备组件安装完成(并已经重启系统),安装导向会运行sql server安装中心。
  当然,你也可以将这些必备组件单独安装。但是,建议使用安装向导进行安装,避免多次重启系统。因为将这两个组件进行捆绑安装,只需一次重启即可。
  自动运行setup.exe (或手动双击 setup.exe) ,会弹出如下窗口:
  当您同意许可条款后,.net 3.5 sp1安装会继续。闪屏会显示正在下载组件,事实上只是从dvd中拷贝。这个过程需要花费一些时间(大约10-20分钟,取决于硬件条件)。
  2.     windows installer 4.5
  同意许可条约。
  其他先决条件列于联机丛书“硬件和软件条件”主题下。
  在 2003中, 会弹出如下窗口:
  在 vista 和 windows server 2008中, 则是这样的:
  安装更新并只需一次重启使更新生效。
  使用安装向导进行安装只需一次重启,而分别安装两个组件会需要两次重启。 更多信息,请参考上一章节中bob ward’s的博客。
  3.     visual studio 2008 sp1
  当你已经安装了visual studio 2008,这步更新是重要的。因为这一步还没有集成到安装向导中,所以需要从网络上下载安装包。但是这个更新并不是必需的,仅当在你需要安装ssis, bids 或 management tools时是需要的。因此,这一步作为组件检测的一部分出现而不是作为全局系统配置检查的一部分出现。
  windows small business server 2011 高级版包括 sql server 2008 r2http://www.microsoft.com/sbs/en/us/editions-overview.aspx.这个版本和标准版的特性相同。区别是sql 2008 sbs 标准版是一个特殊的标准版,该标准版是针对small business server的版本,属于中小型企业套装的一部分,只能和对应的中小型企业套装版的windows small business server 2008一起安装和使用。
  sql server sbs版本需满足以下几个条件:
  1.这个版本的sql server只能安装在:
  windows server 2008 standard
  windows server 2008 standard without hyper-v
  windows small business server 2008
  windows server 2008 for windows essential server solutions
  windows server 2008 without hyper-v for windows essential server solutions
  请注意: sql server 2008 r2 standard for small business是可以安装在windows server 2008 enterprise上,但是sql server 2008 standard for small business则不可以。
  2.windows server必须加入一个域,并且是active directory forest的根
  3.该域和其他域不存在信任关系
  4.该域不能有任何子域
  5.该域中的用户和设备总和不超过75
  6.客户不能同时在该域的其他操作系统中运行相同序列号的sql server软件
  如果检查失败,你可能看到如下信息: "operating system supported for edition” topic.
  clicking in the failed status shows the following message:
  ---------------------------
  rule check result
  ---------------------------
  rule "operating system supported for edition" failed.
  this sql server edition is not supported on this operating system. see sql server
  books online for information about supported operating systems for sql small
  business server edition.
  ---------------------------
  如果你发现你的服务器并没有在任何一个域中,解决这个问题的最直接的办法是利用“开始->运行->dcpromo”为他创建一个新域。其他需要连接sql server的机器则不需要在这个域中。


顺其自然evo 2014-12-05 12:19
]]>
alwayson可用性组功能测试(2)-sql server群集故障转移http://www.blogjava.net/qileilove/archive/2014/12/05/421074.html顺其自然evo顺其自然evofri, 05 dec 2014 03:41:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/05/421074.htmlhttp://www.blogjava.net/qileilove/comments/421074.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/05/421074.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421074.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421074.html 三、  server群集故障转移对alwayson可用性组的影响
  1. 主副本在sql server群集clustest03/clustest03上
  1.1将节点转移server02.以下是故障转移界面。
  1.2 服务脱机,alwayson自然脱机,但侦听ip并没有脱机。
  1.3 sql服务联机后,侦听ip【10.0.0.224】会脱机重启,alwayson资源组联机
  2. 主副本在server03的服务上
  2.1 当前主副本在server03上,sql server故障转移对可用性组没有影响。以下转移脱机界面。
  测试总结
  a、 若主副本在sql 群集上,当服务脱机时候,侦听ip并不会脱机,alwayson会脱机;可用组不可用。
  b、 当服务重新联机,侦听ip会脱机重新联机,侦听ip会发生顺断。
  c、 重新联机到alwayson连接过程使用20秒左右。
  d、 当主副本不在sql群集上,群集的故障转移对可用性组没有影响。
相关文章


顺其自然evo 2014-12-05 11:41
]]>
聊聊oracle外键约束的几个操作选项http://www.blogjava.net/qileilove/archive/2014/12/03/420963.html顺其自然evo顺其自然evowed, 03 dec 2014 05:35:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/03/420963.htmlhttp://www.blogjava.net/qileilove/comments/420963.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/03/420963.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420963.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420963.html关系型是以数据表和关系作为两大对象基础。数据表是以二维关系将数据组织在dbms中,而关系建立数据表之间的关联,搭建现实对象模型。主外键是任何数据库系统都需存在的约束对象,从对象模型中的业务逻辑加以抽象,作为物理设计的一个部分在数据库中加以实现。
  外键是维护参照完整性的重要手段,大多数情况下的外键都是紧密关联关系。外键约束的作用,是保证字表某个字段取值全都与另一个数据表主键字段相对应。也就是说,只要外键约束存在并有效,就不允许无参照取值出现在字表列中。具体在oracle数据库中,外键约束还是存在一些操作选项的。本篇主要从实验入手,介绍常见操作选项。
  二、环境介绍
  笔者选择oracle 11gr2进行,具体版本号为11.2.0.4。
sql> select * from v$version;
banner
--------------------------------------------------------------------------------
oracle database 11g enterprise edition release 11.2.0.4.0 - 64bit production
pl/sql release 11.2.0.4.0 - production
core      11.2.0.4.0     production
tns for 64-bit : version 11.2.0.4.0 - production
nlsrtl version 11.2.0.4.0 – production
  创建数据表prim和child,对应数据插入。
sql> create table prim (v_id number(3), v_name varchar2(100));
table created
sql> alter table prim add constraint pk_prim primary key (v_id);
table altered
sql> create table child (c_id number(3), v_id number(3), c_name varchar2(100));
table created
sql> alter table child add constraint pk_child primary key (c_id);
table altered
  二、默认外键行为
  首先我们查看默认外键行为方式。
  sql> alter table child
  2    add constraint fk_child_prim foreign key (v_id)
  3    references prim (v_id)
  4  ;
  在没有额外参数加入的情况下,oracle外键将严格按照标准外键方式。
  --在有子记录情况下,强制删除主表记录;
  sql> delete prim where v_id=2;
  delete prim where v_id=2
  ora-02292:违反完整约束条件(a.fk_child_prim) - 已找到子记录
  --在存在子表记录情况下,更改主表记录;
  sql> update prim set v_id=4 where v_id=2;
  update prim set v_id=4 where v_id=2
  ora-02292:违反完整约束条件(a.fk_child_prim) - 已找到子记录
  --修改子表记录
  sql> update child set v_id=5 where v_id=2;
  update child set v_id=5 where v_id=2
  ora-02291: 违反完整约束条件 (a.fk_child_prim) - 未找到父项关键字
  上面实验说明:在默认的oracle外键配置条件下,只要有子表记录存在,主表记录是不允许修改或者删除的。子表记录也必须时刻保证参照完整性。
 三、on delete cascade
  对于应用开发人员而言,严格外键约束关系是比较麻烦的。如果直接操作数据库记录,就意味着需要手工处理主子表关系,处理删除顺序问题。on delete cascade允许了一种“先删除主表,连带删除子表记录”的功能,同时确保数据表整体参照完整性。
  创建on delete cascade外键,只需要在创建外键中添加相应的子句。
  sql> alter table child add constraint fk_child_prim foreign key(v_id) references prim(v_id) on delete cascade;
  table altered
  测试:
sql> delete prim where v_id=2;
1 row deleted
sql> select * from prim;
v_id v_name
---- --------------------------------------------------------------------------------
1 kk
3 iowkd
sql> select * from child;
c_id v_id c_name
---- ---- --------------------------------------------------------------------------------
1    1 kll
2    1 ddkll
3    1 43kll
sql> rollback;
rollback complete
  删除主表操作成功,对应的子表记录被连带自动删除。但是其他操作依然是不允许进行。
  sql> update prim set v_id=4 where v_id=2;
  update prim set v_id=4 where v_id=2
  ora-02292:违反完整约束条件(a.fk_child_prim) - 已找到子记录
  sql> update child set v_id=5 where v_id=2;
  update child set v_id=5 where v_id=2
  ora-02291: 违反完整约束条件 (a.fk_child_prim) - 未找到父项关键字
  on delete cascade被称为“级联删除”,对开发人员来讲是一种方便的策略,可以直接“无视”子记录而删掉主记录。但是,一般情况下,数据库设计人员和dba一般都不推荐这样的策略。
  究其原因,还是由于系统业务规则而定。on delete cascade的确在一定程度上很方便,但是这种自动操作在一些业务系统中是可能存在风险的。例如:一个系统中存在一个参数引用关系,这个参数被引用到诸如合同的主记录中。按照业务规则,如果这个参数被引用过,就不应当被删除。如果我们设置了on delete cascade外键,连带的合同记录就自动的被“干掉”了。开发参数模块的同事一般情况下,也没有足够的“觉悟”去做手工判定。基于这个因素,我们推荐采用默认的强约束关联,起码不会引起数据丢失的情况。
  四、on delete set null
  除了直接删除记录,oracle还提供了一种保留子表记录的策略。注意:外键约束本身不限制字段为空的问题。如果一个外键被设置为on delete set null,当删除主表记录的时候,无论是否存在子表对应记录,主表记录都会被删除,子表对应列被清空。
  sql> alter table child drop constraint fk_child_prim;
  table altered
  sql> alter table child add constraint fk_child_prim foreign key(v_id) references prim(v_id) on delete set null;
  table altered
  删除主表记录。
sql> delete prim where v_id=2;
1 row deleted
sql> select * from prim;
v_id v_name
---- --------------------------------------------------------------------------------
1 kk
3 iowkd
sql> select * from child;
c_id v_id c_name
---- ---- --------------------------------------------------------------------------------
1    1 kll
2    1 ddkll
3    1 43kll
4      43kll
5      4ll
sql> rollback;
rollback complete
  主表记录删除,子表外键列被清空。其他约束动作没有变化。
  sql> update prim set v_id=4 where v_id=2;
  update prim set v_id=4 where v_id=2
  ora-02292:违反完整约束条件(a.fk_child_prim) - 已找到子记录
  sql> update child set v_id=5 where v_id=2;
  update child set v_id=5 where v_id=2
  ora-02291: 违反完整约束条件 (a.fk_child_prim) - 未找到父项关键字
  那么,下一个问题是:如果外键列不能为空,会怎么样呢?
sql> desc child;
name   type          nullable default comments
------ ------------- -------- ------- --------
c_id   number(3)
v_id   number(3)     y
c_name varchar2(100) y
sql> alter table child modify v_id not null;
table altered
sql> desc child;
name   type          nullable default comments
------ ------------- -------- ------- --------
c_id   number(3)
v_id   number(3)
c_name varchar2(100) y
sql> delete prim where v_id=2;
delete prim where v_id=2
ora-01407: 无法更新 ("a"."child"."v_id")为 null
  更改失败~
  五、传说中的on update cascade
  on update cascade被称为“级联更新”,是关系数据库理论中存在的一种外键操作类型。这种类型指的是:当主表的记录被修改(主键值修改),对应子表的外键列值连带的进行修改。
  sql> alter table child add constraint fk_child_prim foreign key(v_id) references prim(v_id) on update cascade;
  alter table child add constraint fk_child_prim foreign key(v_id) references prim(v_id) on update cascade
  ora-00905: 缺失关键字
  目前的oracle版本中,似乎还不支持on update cascade功能。oracle在官方服务中对这个问题的阐述是:在实际系统开发环境中,直接修改主键的情况是比较少的。所以,也许在将来的版本中,这个特性会进行支持。
  六、结论
  oracle外键是我们日常比较常见的约束类型。在很多专家和业界人员的讨论中,我们经常听到“使用外键还是系统编码”的争论。支持外键策略的一般都是数据库专家和“大撒把”的设计师,借助数据库天然的特性,可以高效实现功能。支持系统编码的人员大都是“对象派”等新派人员,相信可以借助系统前端解决所有问题。
  笔者对外键的观点是“适度外键,双重验证”。外键要设计在最紧密的引用关系中,对验证动作,前端和数据库端都要进行操作。外键虽然可以保证最后安全渠道,但是不能将正确易于接受的信息反馈到前端。前端开发虽然比较直观,但是的确消耗精力。所以,把握适度是重要的出发点。


顺其自然evo 2014-12-03 13:35
]]>
sql优化中索引列使用函数之灵异事件http://www.blogjava.net/qileilove/archive/2014/12/03/420964.html顺其自然evo顺其自然evowed, 03 dec 2014 05:35:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/03/420964.htmlhttp://www.blogjava.net/qileilove/comments/420964.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/03/420964.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420964.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420964.html 在优化内容中有一种说法说的是避免在索引列上使用函数、运算等操作,否则优化器将不使用索引而使用全表扫描,但是也有一些例外的情况,今天我们就来看看该灵异事件。
  一般而言,以下情况都会使oracle的优化器走全表扫描,举例:
  1.         substr(hbs_bh,1,4)=’5400’,优化处理:hbs_bh like ‘5400%’
  2.         trunc(sk_rq)=trunc(sysdate), 优化处理:sk_rq>=trunc(sysdate) and sk_rq
  3.         进行了显式或隐式的运算的字段不能进行索引,如:
  ss_df 20>50,优化处理:ss_df>30
  'x' || hbs_bh>’x5400021452’,优化处理:hbs_bh>'5400021542'
  sk_rq 5=sysdate,优化处理:sk_rq=sysdate-5
  4.         条件内包括了多个本表的字段运算时不能进行索引,如:ys_df>cx_df,无法进行优化
  qc_bh || kh_bh='5400250000',优化处理:qc_bh='5400' and kh_bh='250000'
  5.  避免出现隐式类型转化
  hbs_bh=5401002554,优化处理:hbs_bh='5401002554',注:此条件对hbs_bh 进行隐式的to_number转换,因为hbs_bh字段是字符型。
  有一些其它的例外情况,如果select 后边只有索引列且where查询中的索引列含有非空约束的时候,以上规则不适用,如下示例:
  先给出所有脚本及结论:
  drop table t  purge;
  create table t  nologging as select *  from    dba_objects d ;
  create   index ind_objectname on  t(object_name);
  select t.object_name from t where t.object_name ='t';        --走索引
  select t.object_name from t where upper(t.object_name) ='t';       --不走索引
  select t.object_name from t where upper(t.object_name) ='t' and t.object_name is not null ;           --走索引  (index fast full scan)
  select t.object_name from t where upper(t.object_name) ||'aaa' ='t'||'aaa' and t.object_name is not null ;     --走索引  (index fast full scan)
  select t.object_name,t.owner from t where upper(t.object_name) ||'aaa' ='t'||'aaa' and t.object_name is not null ;     --不走索引
  代码:
c:\users\华荣>sqlplus lhr/lhr@orclasm
sql*plus: release 11.2.0.1.0 production on 星期三 11月 12 10:52:29 2014
凯发天生赢家一触即发官网 copyright (c) 1982, 2010, oracle.  all rights reserved.
连接到:
oracle database 11g enterprise edition release 11.2.0.3.0 - 64bit production
with the partitioning, automatic storage management, olap, data mining
and real application testing options
sql>
sql>
sql> drop table t  purge;
表已删除。
sql> create table t  nologging as select *  from    dba_objects d ;
表已创建。
sql>  create   index ind_objectname on  t(object_name);
索引已创建。
 ---- t表所有列均可以为空
sql> desc t
name                      null?    type
----------------------------------------- -------- ----------------------------
owner                               varchar2(30)
object_name                         varchar2(128)
subobject_name                      varchar2(30)
object_id                           number
data_object_id                      number
object_type                         varchar2(19)
created                             date
last_ddl_time                       date
timestamp                           varchar2(19)
status                              varchar2(7)
temporary                           varchar2(1)
generated                           varchar2(1)
secondary                           varchar2(1)
namespace                           number
edition_name                        varchar2(30)
sql>
sql>  set autotrace traceonly;
sql>  select t.object_name from t where t.object_name ='t';
执行计划
----------------------------------------------------------
plan hash value: 4280870634
-----------------------------------------------------------------------------------
| id  | operation        | name           | rows  | bytes | cost (%cpu)| time     |
-----------------------------------------------------------------------------------
|   0 | select statement |                |     1 |    66 |     3   (0)| 00:00:01 |
|*  1 |  index range scan| ind_objectname |     1 |    66 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
1 - access("t"."object_name"='t')
note
-----
- dynamic sampling used for this statement (level=2)
- sql plan baseline "sql_plan_503ygb00mbj6k165e82cd" used for this statement
统计信息
----------------------------------------------------------
34  recursive calls
43  db block gets
127  consistent gets
398  physical reads
15476  redo size
349  bytes sent via sql*net to client
359  bytes received via sql*net from client
2  sql*net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
sql>  select t.object_name from t where upper(t.object_name) ='t';
执行计划
----------------------------------------------------------
plan hash value: 1601196873
--------------------------------------------------------------------------
| id  | operation         | name | rows  | bytes | cost (%cpu)| time     |
--------------------------------------------------------------------------
|   0 | select statement  |      |    12 |   792 |   305   (1)| 00:00:04 |
|*  1 |  table access full| t    |    12 |   792 |   305   (1)| 00:00:04 |
--------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
1 - filter(upper("t"."object_name")='t')
note
-----
- dynamic sampling used for this statement (level=2)
- sql plan baseline "sql_plan_9p76pys5gdb2b94ecae5c" used for this statement
统计信息
----------------------------------------------------------
29  recursive calls
43  db block gets
1209  consistent gets
1092  physical reads
15484  redo size
349  bytes sent via sql*net to client
359  bytes received via sql*net from client
2  sql*net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
sql>  select t.object_name from t where upper(t.object_name) ='t' and t.object_name is not null ;
执行计划
----------------------------------------------------------
plan hash value: 3379870158
---------------------------------------------------------------------------------------
| id  | operation            | name           | rows  | bytes | cost (%cpu)| time     |
---------------------------------------------------------------------------------------
|   0 | select statement     |                |    51 |  3366 |   110   (1)| 00:00:02 |
|*  1 |  index fast full scan| ind_objectname |    51 |  3366 |   110   (1)| 00:00:02 |
---------------------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
1 - filter("t"."object_name" is not null and upper("t"."object_name")='t')
note
-----
- dynamic sampling used for this statement (level=2)
- sql plan baseline "sql_plan_czkarb71kthws18b0c28f" used for this statement
统计信息
----------------------------------------------------------
29  recursive calls
43  db block gets
505  consistent gets
384  physical reads
15612  redo size
349  bytes sent via sql*net to client
359  bytes received via sql*net from client
2  sql*net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
sql>  select t.object_name,t.owner from t where upper(t.object_name) ||'aaa' ='t'||'aaa' and t.object_name is not null ;
执行计划
----------------------------------------------------------
plan hash value: 1601196873
--------------------------------------------------------------------------
| id  | operation         | name | rows  | bytes | cost (%cpu)| time     |
--------------------------------------------------------------------------
|   0 | select statement  |      |    51 |  4233 |   304   (1)| 00:00:04 |
|*  1 |  table access full| t    |    51 |  4233 |   304   (1)| 00:00:04 |
--------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
1 - filter("t"."object_name" is not null and
upper("t"."object_name")||'aaa'='taaa')
note
-----
- dynamic sampling used for this statement (level=2)
- sql plan baseline "sql_plan_au9a1c4hwdtb894ecae5c" used for this statement
统计信息
----------------------------------------------------------
30  recursive calls
44  db block gets
1210  consistent gets
1091  physical reads
15748  redo size
408  bytes sent via sql*net to client
359  bytes received via sql*net from client
2  sql*net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
sql> select t.object_name from t where upper(t.object_name) ||'aaa' ='t'||'aaa' and t.object_name is not null ;
执行计划
----------------------------------------------------------
plan hash value: 3379870158
---------------------------------------------------------------------------------------
| id  | operation            | name           | rows  | bytes | cost (%cpu)| time     |
---------------------------------------------------------------------------------------
|   0 | select statement     |                |    51 |  3366 |   110   (1)| 00:00:02 |
|*  1 |  index fast full scan| ind_objectname |    51 |  3366 |   110   (1)| 00:00:02 |
---------------------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
1 - filter("t"."object_name" is not null and
upper("t"."object_name")||'aaa'='taaa')
note
-----
- dynamic sampling used for this statement (level=2)
- sql plan baseline "sql_plan_1gu36rnh3s2a318b0c28f" used for this statement
统计信息
----------------------------------------------------------
28  recursive calls
44  db block gets
505  consistent gets
6  physical reads
15544  redo size
349  bytes sent via sql*net to client
359  bytes received via sql*net from client
2  sql*net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
sql>
  其实很好理解的,索引可以看成是小表,一般而言索引总是比表本身要小得多,如果select 后需要检索的项目在索引中就可以检索的到那么oracle优化器为啥还去大表中寻找数据呢?


顺其自然evo 2014-12-03 13:35
]]>利用binlog进行数据库的还原http://www.blogjava.net/qileilove/archive/2014/12/03/420962.html顺其自然evo顺其自然evowed, 03 dec 2014 05:34:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/03/420962.htmlhttp://www.blogjava.net/qileilove/comments/420962.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/03/420962.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420962.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420962.html前言:在学习备份的时候,深深的感受到mysql的备份还原功能没有强大;比如一个很常见的恢复场景:基于时间点的恢复,oracle通过rman工具就能够很快的实现的恢复,但是mysql在进行不完全恢复的时候很大的一部分要依赖于mysqlbinlog这个工具运行binlog语句来实现,本文档介绍通过mysqlbinlog实现各种场景的恢复;
  一、环境说明:使用mysqlbinlog工具的前提需要一个数据库的完整性备份,所以需要事先对数据库做一个完整的备份,本文档通过mysqlbackup进行数据库的全备
  二、测试步骤说明:
  数据库的插入准备
  2.1 在时间点a进行一个数据库的完整备份;
  2.2 在时间点b创建一个数据库bkt,并在bkt下面创建一个表john,并插入5条数据;
  2.3 在时间点c往表john继续插入数据到10条;
  数据库的恢复工作
  2.4 恢复数据库到时间点a,然后检查数据库表的状态;
  2.5 恢复数据库到时间点b,检查相应的系统状态;
  2.6 恢复数据库到时间点c,并检查恢复的状态;
  三、场景模拟测试步骤(备份恢复是一件很重要的事情)
  3.1 执行数据库的全备份;
  [root@mysql01 backup]# mysqlbackup --user=root --password --backup-dir=/backup backup-and-apply-log //运行数据库的完整备份
  3.2 创建数据库、表并插入数据
mysql> select current_timestamp;
---------------------
| current_timestamp |
---------------------
| 2014-11-26 17:51:27 |
---------------------
1 row in set (0.01 sec)
mysql> show databases; //尚未创建数据库bkt
--------------------
| database |
--------------------
| information_schema |
| john |
| mysql |
| performance_schema |
--------------------
4 rows in set (0.03 sec)
mysql> ctrl-c --
aborted
[root@mysql02 data]# mysql -uroot -p
enter password:
welcome to the mysql monitor. commands end with ; or \\g.
your mysql connection id is 2
server version: 5.5.36-log source distribution
凯发天生赢家一触即发官网 copyright (c) 2000, 2014, oracle and/or its affiliates. all rights reserved.
oracle is a registered trademark of oracle corporation and/or its
affiliates. other names may be trademarks of their respective
owners.
type \'help;\' or \'\\h\' for help. type \'\\c\' to clear the current input statement.
mysql> show master status;
------------------ ---------- -------------- ------------------
| file | position | binlog_do_db | binlog_ignore_db |
------------------ ---------- -------------- ------------------
| mysql-bin.000001 | 107 | | | //当前数据库log的pos状态
------------------ ---------- -------------- ------------------
1 row in set (0.00 sec)
mysql> select current_timestamp; //当前的时间戳 当前时间点a
---------------------
| current_timestamp |
---------------------
| 2014-11-26 17:54:12 |
---------------------
1 row in set (0.00 sec)
mysql> create database bkt; //创建数据库bkt
query ok, 1 row affected (0.01 sec)
mysql> create table john (id varchar(32));
error 1046 (3d000): no database selected
mysql> use bkt;
error 1049 (42000): unknown database \'bkt\'
mysql> use bkt;
database changed
mysql> create table john (id varchar(32));
query ok, 0 rows affected (0.02 sec)
mysql> insert into john values(\'1\');
query ok, 1 row affected (0.01 sec)
mysql> insert into john values(\'2\');
query ok, 1 row affected (0.01 sec)
mysql> insert into john values(\'3\');
query ok, 1 row affected (0.00 sec)
mysql> insert into john values(\'4\');
query ok, 1 row affected (0.01 sec)
mysql> insert into john values(\'5\');
query ok, 1 row affected (0.01 sec)
mysql> select current_timestamp; //插入5条数据后数据库的时间点b,记录该点便于数据库的恢复
---------------------
| current_timestamp |
---------------------
| 2014-11-26 17:55:53 |
---------------------
1 row in set (0.00 sec)
mysql> show master status;
------------------ ---------- -------------- ------------------
| file | position | binlog_do_db | binlog_ignore_db |
------------------ ---------- -------------- ------------------
| mysql-bin.000001 | 1204 | | | //当前binlog的pos位置
------------------ ---------- -------------- ------------------
1 row in set (0.00 sec)
 3.3 设置时间点c的测试
mysql> insert into john values(\'6\');
query ok, 1 row affected (0.02 sec)
mysql> insert into john values(\'7\');
query ok, 1 row affected (0.01 sec)
mysql> insert into john values(\'8\');
query ok, 1 row affected (0.01 sec)
mysql> insert into john values(\'9\');
query ok, 1 row affected (0.01 sec)
mysql> insert into john values(\'10\');
query ok, 1 row affected (0.03 sec)
mysql> show master status;
------------------ ---------- -------------- ------------------
| file | position | binlog_do_db | binlog_ignore_db |
------------------ ---------- -------------- ------------------
| mysql-bin.000001 | 2125 | | |
------------------ ---------- -------------- ------------------
1 row in set (0.00 sec)
mysql> select current_timestamp;
---------------------
| current_timestamp |
---------------------
| 2014-11-26 17:58:08 |
---------------------
1 row in set (0.00 sec)
  3.4 以上的操作完成之后,便可以执行数据库的恢复测试
[root@mysql02 data]# mysqlbackup --defaults-file=/backup/server-my.cnf --datadir=/data/mysql --backup-dir=/backup/ copy-back
mysql enterprise backup version 3.11.0 linux-3.8.13-16.2.1.el6uek.x86_64-x86_64 [2014/08/26]
凯发天生赢家一触即发官网 copyright (c) 2003, 2014, oracle and/or its affiliates. all rights reserved.
mysqlbackup: info: starting with following command line ...
mysqlbackup --defaults-file=/backup/server-my.cnf --datadir=/data/mysql
--backup-dir=/backup/ copy-back
mysqlbackup: info:
important: please check that mysqlbackup run completes successfully.
at the end of a successful \'copy-back\' run mysqlbackup
prints \"mysqlbackup completed ok!\".
141126 17:59:58 mysqlbackup: info: meb logfile created at /backup/meta/meb_2014-11-26.17-59-58_copy_back.log
--------------------------------------------------------------------
server repository options:
--------------------------------------------------------------------
datadir = /data/mysql
innodb_data_home_dir = /data/mysql
innodb_data_file_path = ibdata1:10m:autoextend
innodb_log_group_home_dir = /data/mysql/
innodb_log_files_in_group = 2
innodb_log_file_size = 5242880
innodb_page_size = null
innodb_checksum_algorithm = none
--------------------------------------------------------------------
backup config options:
--------------------------------------------------------------------
datadir = /backup/datadir
innodb_data_home_dir = /backup/datadir
innodb_data_file_path = ibdata1:10m:autoextend
innodb_log_group_home_dir = /backup/datadir
innodb_log_files_in_group = 2
innodb_log_file_size = 5242880
innodb_page_size = 16384
innodb_checksum_algorithm = none
mysqlbackup: info: creating 14 buffers each of size 16777216.
141126 17:59:58 mysqlbackup: info: copy-back operation starts with following threads
1 read-threads 1 write-threads
mysqlbackup: info: could not find binlog index file. if this is online backup then server may not have started with --log-bin.
hence, binlogs will not be copied for this backup. point-in-time-recovery will not be possible.
141126 17:59:58 mysqlbackup: info: copying /backup/datadir/ibdata1.
mysqlbackup: progress in mb: 200 400 600
141126 18:00:22 mysqlbackup: info: copying the database directory \'john\'
141126 18:00:23 mysqlbackup: info: copying the database directory \'mysql\'
141126 18:00:23 mysqlbackup: info: copying the database directory \'performance_schema\'
141126 18:00:23 mysqlbackup: info: completing the copy of all non-innodb files.
141126 18:00:23 mysqlbackup: info: copying the log file \'ib_logfile0\'
141126 18:00:23 mysqlbackup: info: copying the log file \'ib_logfile1\'
141126 18:00:24 mysqlbackup: info: creating server config files server-my.cnf and server-all.cnf in /data/mysql
141126 18:00:24 mysqlbackup: info: copy-back operation completed successfully.
141126 18:00:24 mysqlbackup: info: finished copying backup files to \'/data/mysql\'
mysqlbackup completed //数据库恢复完成
  授权并打开数据库
  [root@mysql02 data]# chmod -r 777 mysql //需要授权后才能打开
  [root@mysql02 data]# cd mysql
  [root@mysql02 mysql]# ll
  总用量 733220
-rwxrwxrwx. 1 root root 305 11月 26 18:00 backup_variables.txt
-rwxrwxrwx. 1 root root 740294656 11月 26 18:00 ibdata1
-rwxrwxrwx. 1 root root 5242880 11月 26 18:00 ib_logfile0
-rwxrwxrwx. 1 root root 5242880 11月 26 18:00 ib_logfile1
drwxrwxrwx. 2 root root 4096 11月 26 18:00 john
drwxrwxrwx. 2 root root 4096 11月 26 18:00 mysql
drwxrwxrwx. 2 root root 4096 11月 26 18:00 performance_schema
-rwxrwxrwx. 1 root root 8488 11月 26 18:00 server-all.cnf
-rwxrwxrwx. 1 root root 1815 11月 26 18:00 server-my.cnf //没有bkt数据库
[root@mysql02 mysql]# service mysqld start //启动数据库
  3.5 进行数据库的恢复到时间点b
  [root@mysql02 mysql2]# pwd //备份的时候,需要备份binlog日志,之前的binlog目录为/data/mysql2
  /data/mysql2
  [root@mysql02 mysql2]# mysqlbinlog --start-position=107 --stop-position=1203 mysql-bin.000001| mysql -uroot -p //根据post的位置进行恢复,当前的pos位置为107,恢复到pos位置到1203
enter password:
[root@mysql02 mysql2]# mysql -uroot -p
enter password:
welcome to the mysql monitor. commands end with ; or \\g.
your mysql connection id is 3
server version: 5.5.36-log source distribution
凯发天生赢家一触即发官网 copyright (c) 2000, 2014, oracle and/or its affiliates. all rights reserved.
oracle is a registered trademark of oracle corporation and/or its
affiliates. other names may be trademarks of their respective
owners.
type \'help;\' or \'\\h\' for help. type \'\\c\' to clear the current input statement.
mysql> show databases;
--------------------
| database |
--------------------
| information_schema |
| bkt |
| john |
| mysql |
| performance_schema |
--------------------
5 rows in set (0.02 sec)
mysql> use bkt
database changed
mysql> show tables;
---------------
| tables_in_bkt |
---------------
| john |
---------------
1 row in set (0.00 sec)
mysql> select * from john;
------
| id |
------
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
------
5 rows in set (0.01 sec) //查看数据库恢复成功
  3.6 恢复数据库到时间点c
[root@mysql02 mysql2]# mysqlbinlog --start-date=\"2014-11-27 09:21:56\" --stop-date=\"2014-11-27 09:22:33\" mysql-bin.000001| mysql -uroot -p123456 //本次通过基于时间点的恢复,恢复到时间点c
warning: using unique option prefix start-date instead of start-datetime is deprecated and will be removed in a future release. please use the full name instead.
warning: using unique option prefix stop-date instead of stop-datetime is deprecated and will be removed in a future release. please use the full name instead.
[root@mysql02 mysql2]# mysql -uroot -p
enter password:
welcome to the mysql monitor. commands end with ; or \\g.
your mysql connection id is 6
server version: 5.5.36-log source distribution
凯发天生赢家一触即发官网 copyright (c) 2000, 2014, oracle and/or its affiliates. all rights reserved.
oracle is a registered trademark of oracle corporation and/or its
affiliates. other names may be trademarks of their respective
owners.
type \'help;\' or \'\\h\' for help. type \'\\c\' to clear the current input statement.
mysql> show databases;
--------------------
| database |
--------------------
| information_schema |
| bkt |
| john |
| mysql |
| performance_schema |
--------------------
5 rows in set (0.00 sec)
mysql> use bkt
database changed
mysql> select * from john;
------
| id |
------
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
------
10 rows in set (0.00 sec) //经过检查成功恢复到时间点c
  四、mysqlbinlog的其他总结:以上是利用binlog文件进行基于时间点和binlog的pos位置恢复的测试,mysqlbinlog的使用还有很多功能,运行mysqlbinlog --help可以查看相应参数;
  4.1 查看binlog的内容:[root@mysql02 mysql2]# mysqlbinlog mysql-bin.000001
  4.2 mysqlbinlog的其他常用参数:
  -h  根据数据库的ip
  -p  根据数据库所占用的端口来分
  -server-id 根据数据库serverid来还原(在集群中很有用)
  -d  根据数据库名称
  例如: [root@mysql02 mysql2]# mysqlbinlog -d bkt mysql-bin.000001 //还原bkt数据库的信息


顺其自然evo 2014-12-03 13:34
]]>
探索oracle之数据库升级一 升级补丁修复概述http://www.blogjava.net/qileilove/archive/2014/12/03/420961.html顺其自然evo顺其自然evowed, 03 dec 2014 05:33:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/03/420961.htmlhttp://www.blogjava.net/qileilove/comments/420961.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/03/420961.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420961.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420961.html 一、 升级路线图
  无论你是谁,要想做升级,我想一定离不开如下这张升级线路图;企业中数据库的升级是一个浩大的工程,但是却又必不可少,小在打一个psu解决一个简单的问题或实现某个功能,大到打安装patch对数据库版本升级,都是作为一名合格的dba必备的技能。再后面的几篇博客当中将详细讲述如何将数据库从11.2.0.3.0升级到11.2.0.4并且打上最新的opatch之后再升级到 12c。
  二、 升级类型:
  11.2.0.1.0 ----------11.2.0.4.0---------11.2.0.4.4-----------12.2.0.1.0
  cpu                      psu
  update                             upgrade
  1. 什么是psu/cpu?
  cpu: critical patch update   (spu: security patch update)
  oracle对于其产品每个季度发行一次的安全补丁包,通常是为了修复产品中的安全隐患。
  psu: patch set updates
  oracle对于其产品每个季度发行一次的补丁包,包含了的修复。oracle选取被用户下载数量多的,并且被验证过具有较低风险的补丁放入到每个季度的psu中。在每个psu中不但包含bug的修复而且还包含了最新的cpu。
  2. 如何查找最新的psu
  每个数据库版本都有自己的psu,psu版本号体现在数据库版本的最后一位,比如最新的10.2.0.5的psu是10.2.0.5.6,而11.2.0.3的最新psu则是11.2.0.4.3。
  mos站点中oraclerecommended patches — oracle database [id 756671.1] 文档中查到各个产品版本最新的psu。
  如果你记不住这个文档号,那么在mos中以“psu”为关键字搜索,通常这个文档会显示在搜索结果的最前面。
  注意:必须购买了oracle基本服务获取了csi号以后才有权限登陆mos站点。
  upgrade与update
  首先,我们针对所使用的数据库可能会进行如下措施,版本升级或补丁包升级,那何为版本升级、何为补丁包升级呢?
  比如我的当前数据库是10gr2版本,但公司最近有个升级计划,把这套数据库升级到当下最新的11gr2,这种大版本间升级动作即为upgrade。根据公司计划在原厂工程师和dba共同努力下,数据库已升级到11gr2,当下版本为11.2.0.4.0。这时候原厂工程师推荐把最新的psu给打上,获得老板的批准之后,我们又把数据库进行补丁包的升级,应用了psu patch:18522509之后,数据库版本现在成为11.2.0.4.3,这个过程即是update。
  不得不再次提醒,upgrade和update都希望在获得原厂的支持下进行,尤其是upgrade,这对于企业来说是个非常大的动作!
  psr(patch set release)和 psu(patch set update)
  8i、9i、10g、11g、12c这是其主要版本号,每一版本会陆续有两至三个发行版,如10.1,10.2,和11.1,11.2分别是10g和11g的两个发行版。对于每一个发行版软件中发现的bug,给出相应的修复补丁。每隔一定时期,会将所有补丁集成到软件中,经过集成后,进行发布,也称为psr(patch set release)。以10.2为例,10.2.0.1.0是基础发行版,至今已有三个psr发布,每个psr修改5位版本号的第4位,最新10.2的psr为10.2.0.4.0。(11.1.0.6.0是11.1的基础发行版,11.1.0.7.0是第一次psr)。
  在某个psr之后编写的补丁,在还没有加入到下一个psr之前,以个别补丁(interimpatch)的形式提供给客户。某个个别补丁是针对oracle公司发现的或客户报告的某一个bug编写的补丁,多个个别补丁之间一同安装时可能会有冲突,即同一个目标模块分别进行了不同的修改。另外,即便在安装时没有发现冲突,由于没有进行严格的集成测试,运行过程中由于相互作用是否会发生意外也不能完全排除。
  除去修改功能和性能bug的补丁,还有应对安全漏洞的安全补丁。oracle公司定期(一年四期)发布安全补丁集,称之为cpu(critical patch updates)。
  由于数据库在信息系统的核心地位,对其性能和安全性的要求非常高。理应及时安装所有重要补丁。另外一个方面,基于同样的理由,要求数据库系统必须非常稳定,安装补丁而导致的系统故障和性能下降同样不可接受。dba经常面临一个非常困难的选择:对于多个修复重要bug的个别补丁是否安装。不安装,失去预防故障发生的机会,以后故障发生时,自己是无作为;安装,如果这些补丁中存在着倒退bug,或者相互影响,以后发生由于安装补丁而造成的故障时,自己则是无事生非!而等待下一个psr,一般又需要一年时间。因此,出了psu(patch set update)
  三、oracle 版本说明
  oracle 的版本号很多,先看11g的一个版本号说明:
  注意:在oracle 9.2 版本之后, oracle 的maintenance release number 是在第二数字位更改。而在之前,是在第三个数字位。
  1. major database releasenumber
  第一个数字位,它代表的是一个新版本软件,也标志着一些新的功能。如11g,10g。
  2. database maintenancerelease number
  第二个数字位,代表一个maintenancerelease 级别,也可能包含一些新的特性。
  3. fusion middleware releasenumber
  第三个数字位,反应oracle 中间件(oracle fusion middleware)的版本号。
  4. component-specific releasenumber
  第四个数字位,主要是针对组件的发布级别。不同的组件具有不同的号码。 比如oracle 的patch包。
  5. platform-specific releasenumber
  第五个数字位,这个数字位标识一个平台的版本。 通常表示patch 号。


顺其自然evo 2014-12-03 13:33
]]>
使用调用者权限实现schema导向操作http://www.blogjava.net/qileilove/archive/2014/11/28/420808.html顺其自然evo顺其自然evofri, 28 nov 2014 02:44:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/28/420808.htmlhttp://www.blogjava.net/qileilove/comments/420808.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/28/420808.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420808.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420808.html很多时候,我们都会使用存储过程procedure来实现一些脚本工具。通过procedure来实现一些相关的维护、开发,可以大大提高我们日常工作效率。一个朋友最近咨询了关于procedure调用的问题,觉得比较有意思,记录下来供需要的朋友不时之需。
  1、问题描述
  问题背景是这样,朋友在运维一个开发项目,同一个数据库中多个schema内容相同,用于不同的目的。一些开发同步任务促使编写一个程序来实现schema内部或者之间对象操作。从软件版本角度看,维护一份工具脚本是最好的方法,可以避免由于修改造成的版本错乱现象。如何实现一份存储过程脚本,在不同schema下执行效果不同就成为问题。
  将问题简化为如下描述:在schema a里面包括一个存储过程proc,a中还有一个数据表t1。在proc代码中,包括了对t1的操作内容。而schema b中也存在一个数据表t1,并且b拥有一个名为proc的私有同义词synonym指向a.proc。问题是如何让proc根据执行的schema主体不同,访问不同schema的数据表。
  也就是说,如果是a调用proc程序包,操作的就是a schema里面的数据表t1。如果b调用proc程序包,就操作b schema里面的数据表t1。
  2、测试实验一
  为了验证测试,我们模拟了实验环境,来观察现象。选择11gr2进行测试。
sql> select * from v$version;
banner
--------------------------------------------------------------------------------
 database 11g enterprise edition release 11.2.0.4.0 - 64bit production
pl/sql release 11.2.0.4.0 - production
core      11.2.0.4.0     production
tns for 64-bit : version 11.2.0.4.0 - production
nlsrtl version 11.2.0.4.0 – production
创建对应schema和数据表。
sql> create user a identified by a;
user created
sql> create user b identified by b;
user created
sql> grant connect, resource to a,b;
grant succeeded
sql> grant create procedure to a,b;
grant succeeded
sql> grant create synonym to a,b;
grant succeeded
  在schema a下面创建数据表和对应操作存储过程。
sql> conn a/a@sicsdb
connected to oracle database 11g enterprise edition release 11.2.0.4.0
connected as a
sql> create table a(col varchar2(10));
table created
sql> create or replace procedure proc(i_vc_name varchar2) is
2  begin
3    insert into a values (i_vc_name);
4    commit;
5  end proc;
6  /
procedure created
从schema a进行调用动作:
sql> exec proc('iii');
pl/sql procedure successfully completed
sql> select * from a;
col
----------------------------------------
iii
sql> grant execute on proc to b;
grant succeeded
  另外创建schema b数据表对象,并且包括同义词对象。
  sql> conn b/b@sicsdb
  connected to oracle database 11g enterprise edition release 11.2.0.4.0
  connected as b
  sql> create table a(col varchar2(10));
  table created
  sql> create synonym proc for a.proc;
  synonym created
  进行默认情况测试,在schema b中调用存储过程proc,看操作数据表是哪张:
sql> conn b/b@sicsdb
connected to oracle database 11g enterprise edition release 11.2.0.4.0
connected as b
sql> exec proc('jjj');
pl/sql procedure successfully completed
sql> select * from a;
col
----------------------------------------
  schema b中数据表a没有数据,查看schema a中数据表情况:
  sql> select * from a.a;
  col
  --------------------
  jjj
  iii
  实验说明:在默认情况下,不同schema对象调用相同存储过程,其中涉及到的对象都是相同的。也就是oracle存储过程中的“所有者权限”。一旦用户拥有执行存储过程的权限,就意味着在执行体中,使用的是执行体所有者的权限体系。
  那么这个问题似乎是没有办法。执行体指向的是schema a的数据表a。
  3、测试实验二
  与所有者权限对应的另一种模式是“调用者权限”。也就说,对用户是否可以执行该程序体中的对象,完全取决于执行调用用户系统权限和对象权限(注意:非角色权限)。
  笔者一种猜想,如果应用调用者权限,从执行用户权限角度看,是不是可以直接访问自己schema中的对象了。下面通过实验进行证明。
sql> conn a/a@sicsdb
connected to oracle database 11g enterprise edition release 11.2.0.4.0
connected as a
sql>
sql> create or replace procedure proc(i_vc_name varchar2) authid current_user is
2  begin
3    insert into a values (i_vc_name);
4    commit;
5  end proc;
6  /
procedure created
很多时候,我们都会使用存储过程procedure来实现一些脚本工具。通过procedure来实现一些相关的维护、开发,可以大大提高我们日常工作效率。一个朋友最近咨询了关于procedure调用的问题,觉得比较有意思,记录下来供需要的朋友不时之需。
  1、问题描述
  问题背景是这样,朋友在运维一个开发项目,同一个数据库中多个schema内容相同,用于不同的目的。一些开发同步任务促使编写一个程序来实现schema内部或者之间对象操作。从软件版本角度看,维护一份工具脚本是最好的方法,可以避免由于修改造成的版本错乱现象。如何实现一份存储过程脚本,在不同schema下执行效果不同就成为问题。
  将问题简化为如下描述:在schema a里面包括一个存储过程proc,a中还有一个数据表t1。在proc代码中,包括了对t1的操作内容。而schema b中也存在一个数据表t1,并且b拥有一个名为proc的私有同义词synonym指向a.proc。问题是如何让proc根据执行的schema主体不同,访问不同schema的数据表。
  也就是说,如果是a调用proc程序包,操作的就是a schema里面的数据表t1。如果b调用proc程序包,就操作b schema里面的数据表t1。
  2、测试实验一
  为了验证测试,我们模拟了实验环境,来观察现象。选择11gr2进行测试。
sql> select * from v$version;
banner
--------------------------------------------------------------------------------
 database 11g enterprise edition release 11.2.0.4.0 - 64bit production
pl/sql release 11.2.0.4.0 - production
core      11.2.0.4.0     production
tns for 64-bit : version 11.2.0.4.0 - production
nlsrtl version 11.2.0.4.0 – production
创建对应schema和数据表。
sql> create user a identified by a;
user created
sql> create user b identified by b;
user created
sql> grant connect, resource to a,b;
grant succeeded
sql> grant create procedure to a,b;
grant succeeded
sql> grant create synonym to a,b;
grant succeeded
  在schema a下面创建数据表和对应操作存储过程。
sql> conn a/a@sicsdb
connected to oracle database 11g enterprise edition release 11.2.0.4.0
connected as a
sql> create table a(col varchar2(10));
table created
sql> create or replace procedure proc(i_vc_name varchar2) is
2  begin
3    insert into a values (i_vc_name);
4    commit;
5  end proc;
6  /
procedure created


顺其自然evo 2014-11-28 10:44
]]>
php写的从数据库导入到excelhttp://www.blogjava.net/qileilove/archive/2014/11/26/420636.html顺其自然evo顺其自然evowed, 26 nov 2014 07:08:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/26/420636.htmlhttp://www.blogjava.net/qileilove/comments/420636.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/26/420636.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420636.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420636.html原理: 就是原理很分页原理一样! 选取一定数量的数据然后变成数组,接着直接写入文件。接下来继续选取后面没选定数据在变成数组,接着在写入文件!这个解决了内存溢出。但是多cpu还是有个考验! 由于本人刚刚学php(php培训 php教程 )不久,功力不深厚!只能写出这样的东西!
  源码!
  excel类
php code
class excel{
var $header = "
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/tr/rec-html40">";
var $footer = "";
var $lines = array ();
var $worksheet_title = "table1";
function addrow ($array) {
$cells = "";
foreach ($array as $k => $v):
if(is_numeric($v)) {
if(substr($v, 0, 1) == 0) {
$cells .= "" . $v . "n";
} else {
$cells .= "" . $v . "n";
}
} else {
$cells .= "" . $v . "n";
}
endforeach;
$this->lines[] = "n" . $cells . "n";
unset($arry);
}
function setworksheettitle ($title) {
$title = preg_replace ("/[\|:|/|?|*|[|]]/", "", $title);
$title = substr ($title, 0, 31);
$this->worksheet_title = $title;
}
function generatexml ($filename) {
// deliver header (as recommended in php manual)
header("content-type: application/vnd.ms-excel; charset=utf-8");
header("content-disposition: inline; filename="" . $filename . ".xls"");
// print out document to the browser
// need to use stripslashes for the damn ">"
echo stripslashes ($this->header);
echo "nworksheet_title . "">nn";
echo "n";
echo implode ("n", $this->lines);
echo "
n
n";
echo $this->footer;
exit;
}
function write ($filename) // 重点
{
$content= stripslashes ($this->header);
$content.= "nworksheet_title . "">nn";
$content.= "n";
$content.= implode ("n", $this->lines);
$content.= "
n
n";
$content.= $this->footer;//excel文件
//error_log($content, 3,$filename);
if (!file_exists($filename))//判断有没有文件
{
fopen($filename,'a');
}
$fp = fopen($filename,'a');
fwrite($fp, $content);//写入文件
fclose($fp);
unset($this->lines);//清空内存中的数据
}
}
 页面
phpcode
include_once"./include/class.excel.php";//调用excel类
require_once'./include/class.zipfile.php';//调用大包类
$xls=newexcel;//实例化
$w=explode("limit",$where_str);//把where
$p=6000;//分页原理
$a=$ip_list_count/$p;//分页原理
if($ip_list_count%$p==0)//分页原理
else//分页原理
for($i=0;$i<=$a;$i )//循环写出
{
$s=6000*$i;
$ip=$_sg['db']->fetch_all("select*frommain_info".$w[0]."limit".$s.",".$p);//调用自己写的数据库(数据库培训数据库认证)方法,写出数组
$xls->addarray($ip);//调用excel类中addarray方法
xml1=$xls->write("./".$i.".xls");//调用excel类中write方法
unset($ip);
unset($xml1);
sleep(1);
}


顺其自然evo 2014-11-26 15:08
]]>
mysql数据库服务器的cpu占用很高http://www.blogjava.net/qileilove/archive/2014/11/24/420494.html顺其自然evo顺其自然evomon, 24 nov 2014 02:02:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/24/420494.htmlhttp://www.blogjava.net/qileilove/comments/420494.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/24/420494.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420494.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420494.html mysql服务器cpu占用很高
  1.  问题描述
  一个简单的接口,根据传入的号段查询号码归属地,运行脚本,20个并发mysql的cpu就很高,监控发现只有一个select语句,且表建立了索引
  2.  问题原因
  查询语句索引没有命中导致
  开始时的select
select
`province_name`,
`city_name`
from `phoneno_section`
where substring(?, phoneno_section_len) = phoneno_section
limit ?
咨询说where中使用substring函数不行,修改函数为left,语句为
select
`province_name`,
`city_name`
from `conf_phoneno_section`
where left(?, phoneno_section_len) = phoneno_section
limit ?
  测试发现cpu占用还是很高,left函数中的参数是变量不是常量,再次修改select语句,指定left函数中的phoneno_section_len为固定值,cpu占用正常
  3.  mysql索引介绍
  ü  先举个例子
  表a, 字段:  id(自增id),user(用户名),pass(密码),type(类型 0,1),
  索引: user pass 建立联合索引 ,user唯一索引,pass普通索引 ,type 普通索引
  ü  索引命中说明
  (1)select   *   from   a  where user = 't'  and pass = 'p'会命中user pass的联合索引
  (2):  select   *   from   a  where user = 't' or user= 'f'  不能命中任何索引
  (3)sql:  select   *   from   a  where user = 't'会命中user唯一索引
  (4)sql:  select   *   from   a  where pass = 'p'   不能命中任何索引
  (5)select  *  from  a where user = 't'  or   user= 'f' 相对于select  user,pass  from  a  where user = 't'  or   user= 'f'  会慢
  (6)select * from a where length(user) = 3 不能命中
  (7)user唯一索引 、type索引可以删除
  索引就是排序,目前的计算机技术和数学理论还不支持一次同时按照两个关键字进行排序,即使是联合索引,也是先按照最左边的关键字先排,然后在左边的关键字排序基础上再对其他的关键字排序,是一个多次排序的结果。 所以,单表查询,一次最多只能命中一个索引,并且索引必须遵守最左前缀。于是基于索引的结构和最左前缀,像 or ,like '%%'都是不能命中索引的,而like 'aa%'则是可以命中的。
  无论是innodb还是myisam,索引只记录被排序的行的主键或者地址,其他的字段还是需要二次查询,因此,如果查询的字段刚好只是包含在索引中,那么索引覆盖将是高效的。
  如果所有的数据都一样,或者基本一样,那么就没有排序的必要了。像例子中的type只有1或者0,选择性是0.5,极低的样纸,所以可以忽视,即使建立了,也是浪费空间,mysql在查询的时候也会选择丢弃。
  类似最左前缀,查询索引的时候,如果列被应用了函数,那么在查询的时候,是不会用到索引的。道理很简单,函数运算已经改变了列的内容,而原始的索引是对列内容全量排序的。
  综上所述,索引的几个知识点:最左前缀,索引覆盖,索引选择性,列隔离在建立和使用索引的时候需要格外注意。
  4.  mysql索引无效场景补充
  ü  where子句的查询条件里有不等于号(where column!=...),mysql将无法使用索引
  ü  where子句的查询条件里使用了函数(如:where day(column)=...),mysql将无法使用索引,实验中left函数是可以的,但是条件不能是变量,使用left函数且条件是变量,也无法使用索引,left函数之外是否有其它函数有待验证
  ü  在join操作中(需要从多个数据表提取数据时),mysql只有在主键和外键的数据类型相同时才能使用索引,否则即使建立了索引也不会使用
  ü  如果where子句的查询条件里使用了比较操作符like和regexp,mysql只有在搜索模板的第一个字符不是通配符的情况下才能使用索引。比如说,如果查询条件是like 'abc%',mysql将使用索引;如果条件是like '�c',mysql将不使用索引。
  ü  在order by操作中,mysql只有在排序条件不是一个查询条件表达式的情况下才使用索引。尽管如此,在涉及多个数据表的查询里,即使有索引可用,那些索引在加快order by操作方面也没什么作用。
  ü  如果某个数据列里包含着许多重复的值,就算为它建立了索引也不会有很好的效果。比如说,如果某个数据列里包含了净是些诸如“0/1”或“y/n”等值,就没有必要为它创建一个索引。
  只要建立了索引,除了上面提到的索引不会使用的情况下之外,其他情况只要是使用在where条件里,order by 字段,联表字段,索引一般都是有效的。


顺其自然evo 2014-11-24 10:02
]]>
mysql数据库优化技术之数据库表的设计http://www.blogjava.net/qileilove/archive/2014/11/21/420388.html顺其自然evo顺其自然evofri, 21 nov 2014 01:26:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/21/420388.htmlhttp://www.blogjava.net/qileilove/comments/420388.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/21/420388.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420388.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420388.html三范式介绍
  表的范式:只有符合的第一范式,才能满足第二范式,进一步才能满足第三范式。
  1、第一范式:
  表的列具有原子性,不可再分解。只要是关系型都自动满足第一范式。
  数据库的分类:
  关系型数据库:mysql/oracle/sql server/db2等
  非关系型数据库:特点是面向对象或者集合
  nosql数据库:mongodb(特点是面向文档)
  2、第二范式:
  表中的记录是唯一的,就满足第二范式。通常我们设计一个主键来实现。
  主键一般不含业务逻辑,一般是自增的;
  3、第三范式:
  表中不要有冗余数据,即如果表中的信息能够被推导出来就不应该单独的设计一个字段来存放;对字段冗余性的约束,要求字段没有冗余。
  如下表所示,符合三范式要求:
  student表
  class表
  如下表所示,不符合三范式要求:
  student表
  class表
  反三范式案例:
  一个相册下有多个图片,每个图片有各自的浏览次数,相册有总的浏览次数。
  相册浏览表
  图片表:
  如果相册浏览表没有适当的冗余,效率有影响。
  冗余比较可以得出一个结论:1对n时,冗余应当发生在1的一端。


顺其自然evo 2014-11-21 09:26
]]>
各数据库的批量update操作http://www.blogjava.net/qileilove/archive/2014/11/19/420277.html顺其自然evo顺其自然evowed, 19 nov 2014 01:59:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/19/420277.htmlhttp://www.blogjava.net/qileilove/comments/420277.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/19/420277.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420277.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420277.html  一、前言
  mybatis的update元素的用法与insert元素基本相同,因此本篇不打算重复了。本篇仅记录批量update操作的语句,懂得sql语句,那么mybatis部分的操作就简单了。
  注意:下列批量更新语句都是作为一个事务整体执行,要不全部成功,要不全部回滚。
  二、mssql的sql语句
  with r as(
  select 'john' as name, 18 as age, 42 as  id
  union all
  select 'mary' as name, 20 as age, 43 as  id
  union all
  select 'kite' as name, 21 as age, 44 as  id
  )
  update tstudent set name = r.name, age = r.age
  from r where r.id = tstudent.id
  三、mssql、oracle和的sql语句
  update tstudent set name = r.name, age = r.age
  from (
  select 'mary' as name, 12 as age, 42 as id
  union all
  select 'john' as name , 16 as age, 43 as id
  ) as r
  where id = r.id
  四、sqlite的sql语句
  当条更新:
  replace into tstudent(name, age, id)
  values('mary', 12, 42)
  批量更新:
  replace into tstudent(name, age, id)
  select * from (
  select 'mary' as a, 12 as b, 42 as c
  union all
  select 'john' as a, 14 as b, 43 as b
  ) as r
  说明:replace into会根据主键值,决定执行insert操作还是update操作。
  五、总结
  本篇突出mybatis作为半自动orm框架的好处了,全手动操控sql语句怎一个爽字了得。但对码农的sql知识要求也相对增加了不少,倘若针对项目要求再将这些进行二次封装那会轻松比少。


顺其自然evo 2014-11-19 09:59
]]>
mysql分区表功能测试简析http://www.blogjava.net/qileilove/archive/2014/11/19/420271.html顺其自然evo顺其自然evowed, 19 nov 2014 01:08:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/19/420271.htmlhttp://www.blogjava.net/qileilove/comments/420271.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/19/420271.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420271.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420271.html  1.查看版本是否支持分区
  show variables like '%partition%';
   ------------------- -------
  | variable_name     | value |
   ------------------- -------
  | have_partitioning | yes   |
   ------------------- -------
  如果value 为yes 则支持分区,
  2.测试那种存储引擎支持分区
inoodb引擎
mysql> create table engine1(id int) engine=innodb partition by range(id)(partition po values less than(10));
query ok, 0 rows affected (0.01 sec)
mrg_myisam引擎
mysql> create table engine2(id int) engine=mrg_myisam partition by range(id)(partition po values less than(10));
error 1572 (hy000): engine cannot be used in partitioned tables
blackhole引擎
mysql> create table engine3(id int) engine=blackhole partition by range(id)(partition po values less than(10));
query ok, 0 rows affected (0.01 sec)
csv引擎
mysql> create table engine4(id int) engine=csv partition by range(id)(partition po values less than(10));
error 1572 (hy000): engine cannot be used in partitioned tables
memory引擎
mysql> create table engine5(id int) engine=memory partition by range(id)(partition po values less than(10));
query ok, 0 rows affected (0.01 sec)
federated引擎
mysql> create table engine6(id int) engine=federated partition by range(id)(partition po values less than(10));
query ok, 0 rows affected (0.01 sec)
archive引擎
mysql> create table engine7(id int) engine=archive partition by range(id)(partition po values less than(10));
query ok, 0 rows affected (0.01 sec)
myisam 引擎
mysql> create table engine8(id int) engine=myisam partition by range(id)(partition po values less than(10));
query ok, 0 rows affected (0.01 sec)
  3.mysql分区表,分区引擎
  表分区的存储引擎相同
  mysql> create table pengine1(id int) engine=myisam partition by range(id)(partition po values less than(10) engine=myisam, partition p1 values less than(20) engine=myisam);
  query ok, 0 rows affected (0.05 sec)
  表分区的存储引擎不同
  mysql> create table pengine2(id int) engine=myisam partition by range(id)(partition po values less than(10) engine=myisam, partition p1 values less than(20) engine=innodb);
  error 1497 (hy000): the mix of handlers in the partitions is not allowed in this version of mysql
  同一个分区表中的所有分区必须使用同一个存储引擎,并且存储引擎要和主表的保持一致。
 4.分区类型
  range:基于一个连续区间的列值,把多行分配给分区;
  list:列值匹配一个离散集合;
  hash:基于用户定义的表达式的返回值选择分区,表达式对要插入表中的列值进行计算。这个函数可以包含sql中有效的,产生非负整
  数值的任何表达式。
  key:类似于hash分区,区别在于key 分区的表达式可以是一列或多列,且mysql提供自身的hash函数。
  5.range分区maxvalue值 及加分区测试;
  创建表 prange,最后分区一个分区值是maxvalue
  mysql> create table prange(id int) engine=myisam partition by range(id)(partition po values less than(10), partition p1 values less than(20),partition p2 values less than maxvalue);
  query ok, 0 rows affected (0.06 sec)
  加分区
  mysql> alter table prange add partition (partition p3 values less than (20));
  error 1481 (hy000): maxvalue can only be used in last partition definition
  在分区p0前面加个分区
  mysql> alter table prange add partition (partition p3 values less than (1));
  error 1481 (hy000): maxvalue can only be used in last partition definition
  说明有maxvalue值后,直接加分区是不可行的;
  创建表prange1,无maxvalue值
  mysql> create table prange1(id int) engine=myisam partition by range(id)(partition po values less than(10), partition p1 values less than(20),partition p2 values less than (30));  www.2cto.com
  query ok, 0 rows affected (0.08 sec)
  从最大值后加个分区
  mysql> alter table prange1 add partition (partition p3 values less than (40));
  query ok, 0 rows affected (0.02 sec)
  records: 0 duplicates: 0 warnings: 0
  从分区的最小值前加个分区
  mysql> alter table prange1 add partition (partition p43 values less than (1));
  error 1493 (hy000): values less than value must be strictly increasing for each partition
  由此可见,range 的分区方式在加分区的时候,只能从最大值后面加,而最大值前面不可以添加;
  6. 用时间做分区测试
  create table ptime2(id int,createdate datetime) engine=myisam partition by range (to_days(createdate))
  (partition po values less than (20100801),partition p1 values less than (20100901));
  query ok, 0 rows affected (0.01 sec)
  mysql> create table ptime3(id int,createdate datetime) engine=myisam partition by range (createdate)
  (partition po values less than (20100801),partition p1 values less than (20100901));
  error 1491 (hy000): the partition function returns the wrong type
  直接使用时间列不可以,range分区函数返回的列需要是整型。
  mysql> create table ptime6(id int,createdate datetime) engine=myisam partition by range (year(createdate))
  (partition po values less than (2010),partition p1 values less than (2011));
  query ok, 0 rows affected (0.01 sec)
  使用年函数也可以分区。
  7.mysql可用的分区函数
day()
dayofmonth()
dayofweek()
dayofyear()
datediff()
extract()
hour()
microsecond()
minute()
mod()
month()
quarter()
second()
time_to_sec()
to_days()
weekday()
year()
yearweek() 等
 当然,还有floor(),ceiling() 等,前提是使用这两个分区函数的分区健必须是整型。
  要小心使用其中的一些函数,避免犯逻辑性的错误,引起全表扫描。
  比如:
create table ptime11(id int,createdate datetime) engine=myisam partition by range (day(createdate)) (partition po values less than (15),partition p1 values less than (31));
mysql> insert into ptime11 values (1,'2010-06-17');
mysql> explain partitions select count(1) from ptime11 where createdate>'2010-08-17'\g;
*************************** 1. row ***************************
id: 1
select_type: simple
table: ptime11
partitions: po,p1
type: all
possible_keys: null
key: null
key_len: null
ref: null
rows: 5
extra: using where
1 row in set (0.00 sec)
  8.主键及约束测试
  分区健不包含在主键内
  mysql> create table pprimary(id int,createdate datetime,primary key(id)) engine=myisam partition by range (day(createdate)) (partition po values less than (15),partition p1 values less than (31));  www.2cto.com
  error 1503 (hy000): a primary key must include all columns in the table's partitioning function
  分区健包含在主键内
  mysql> create table pprimary1(id int,createdate datetime,primary key(id,createdate)) engine=myisam partition by range (day(createdate)) (partition po values less than (15),partition p1 values less than (31));
  query ok, 0 rows affected (0.05 sec)
  说明分区健必须包含在主键里面。
  mysql> create table pprimary2(id int,createdate datetime,uid char(10),primary key(id,createdate),unique key(uid)) engine=myisam partition by range(to_days(createdate))(partition p0 values less than (20100801),partition p1 values less than (20100901));
  error 1503 (hy000): a unique index must include all columns in the table's partitioning function
  说明在表上建约束索引会有问题,必须把约束索引列包含在分区健内。
  mysql> create table pprimary3(id int,createdate datetime,uid char(10),primary key(id,createdate),unique key(createdate)) engine=myisam partition by range(to_days(createdate))(partition p0 values less than (20100801),partition p1 values less than (20100901));
  query ok, 0 rows affected (0.00 sec)
  虽然在表上可以加约束索引,但是只有包含在分区健内,这种情况在实际应用过程中会遇到问题,这个问题点在以后的mysql 版本中也许会改进。
  9.子分区测试
  只有range和list分区才能有子分区,每个分区的子分区数量必须相同,
  mysql> create table pprimary7(id int,createdate datetime,uid char(10),primary key(id,createdate)) engine=myisam partition by range(to_days(createdate)) subpartition by hash(to_days(createdate))(partition p0 values less than (20100801) ( subpartition so,subpartition s1) ,partition p1 values less than (20100901) (subpartition s0,subpartition s1));  www.2cto.com
  error 1517 (hy000): duplicate partition name s1
  提示了重复的分区名称错误,这和mysql5.1帮助文档中的说明有出入,不知道是不是这个问题在某个小版本中修改过。
  10.mysql分区健null值测试;
  mysql将null值视为0.自动插入最小的分区中。
  11.mysql分区管理测试
  mysql> alter table pprimary4 truncate partition p1;
  error 1064 (42000): you have an error in your sql syntax; check the manual that corresponds to your mysql server version for the right syntax to use near 'truncate partition p1' at line 1
  5.1版本中还不支持这个语法,5.5中已经支持,很好的一个命令;
  alter table reorganize 可以重新组织分区。


顺其自然evo 2014-11-19 09:08
]]>
使用ef操作不同数据库http://www.blogjava.net/qileilove/archive/2014/11/13/420008.html顺其自然evo顺其自然evothu, 13 nov 2014 02:16:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/13/420008.htmlhttp://www.blogjava.net/qileilove/comments/420008.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/13/420008.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420008.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420008.html  最近一直在和作对。
  从安卓平台上给了我个sqlite数据库,要求程序能够读取不同的文件。由于字段实在太多,不愿意直接使用原来直接读取datatable的方式来做,手动写映射太痛苦...于是想起来ef来。
  那么问题来了,学习ef的时候,一般都是直接在app.config或者.config中写入connectionstring,操作一个数据库的时候挺好,但是如果要操作的数据库需要临时指定的话,就比较麻烦,写进去不太合适。
  我的第一个想法,就是使用dbcontext构造函数的重载
public mydbcontext ()
:base("connectionstringorname")
{
}
  这里面可以接受一个连接字符串或者config文件的name。
  p.s. 使用连接字符串的时候,直接填入就可以,使用name的时候,填入的样子类似"name=myconn"
  使用name不合适了,直接使用连接字符串呢,provider怎么指定?不指定会不会直接用 express呢?自己想了想,没有再去试了,应该也是可以的,写完再补。
  第二个办法,就是使用database.connection设置连接字符串,具体方法如下:
public mydbcontext(string connection)
{
database.connection.connectionstring = getsqlitestring(connection);
}
  这里不调用base里面的方法,对于mysqlite,getsqlitestring如下:
private string getsqlitestring(string connect)
{
return "data source=" connect;
}
  这样就能操作connectionstring了,只需要连接的时候传递一个路径就可以了。
  同理,使用其他类型的数据库也可以这么操作,虽然实际上估计这么用的人不多。


顺其自然evo 2014-11-13 10:16
]]>
mysql数据库远程连接开启方法http://www.blogjava.net/qileilove/archive/2014/11/12/419950.html顺其自然evo顺其自然evowed, 12 nov 2014 02:11:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/12/419950.htmlhttp://www.blogjava.net/qileilove/comments/419950.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/12/419950.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419950.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419950.html 第一中方法:比较详细
  以下的主要介绍的是 开启远程连接的时机操作流程,其实开启mysql 数据库远程连接的实际操作步骤并不难,知识方法对错而已,今天我们要向大家描述的是mysql 数据库开启远程连接的时机操作流程。
  1、d:\mysql\bin\>mysql -h localhost -u root
  这样应该可以进入mysql服务器
  复制代码代码如下:
  mysql>update user set host = '%' where user = 'root';
  mysql>select host, user from user;
  2、mysql>grant all privileges on *.* to 'root'@'%' identified by 'mypassword' with grant option
  予任何主机访问数据的权限
  3、mysql>flush privileges
  修改生效
  4、mysql>exit
  退出mysql服务器
  这样就可以在其它任何的主机上以root身份登录啦!
  以上的相关内容就是对mysql 数据库开启远程连接的介绍,望你能有所收获。
  第二种方法:
  1、在控制台执行 mysql -u root -p mysql,系统提示输入数据库root用户的密码,输入完成后即进入mysql控制台,这个命令的第一个mysql是执行命令,第二个mysql是系统数据名称,不一样的。
  2、在mysql控制台执行 grant all privileges on *.* to ‘root'@'%' identified by ‘mypassword' with grant option;
  3、在mysql控制台执行命令中的 ‘root'@'%' 可以这样理解: root是用户名,%是主机名或ip地址,这里的%代表任意主机或ip地址,你也可替换成任意其它用户名或指定唯一的ip地址;'mypassword'是给授权用户指定的登录数据库的密码;另外需要说明一点的是我这里的都是授权所有权限,可以指定部分权限,grant具体操作详情见:http://dev.mysql.com/doc/refman/5.1/en/grant.html
  4、不放心的话可以在mysql控制台执行 select host, user from user; 检查一下用户表里的内容。


顺其自然evo 2014-11-12 10:11
]]>
破解本地mysql数据库密码http://www.blogjava.net/qileilove/archive/2014/11/11/419911.html顺其自然evo顺其自然evotue, 11 nov 2014 02:13:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/11/419911.htmlhttp://www.blogjava.net/qileilove/comments/419911.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/11/419911.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419911.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419911.html 破解本地密码:
  1.用系统管理员登陆系统。
  2.停止mysql的服务。
  :运行net stop mysql关闭数据库
  3.进入命令窗口,然后进入 mysql的安装目录,比如我的安装目录是c:\mysql,进入c:\mysql\bin
  4.跳过权限检查启动mysql,
  c:\mysql\bin>mysqld-nt ––skip-grant-tables
  或则:c:\mysql\bin>mysqld ––skip-grant-tables
  mysqld.exe是微软windows mysql 数据库服务器相关程序。mysqld-nt.exe是mysql daemon数据库服务相关程序。
  5.[未验证]
  重新打开一个窗口
  进入c:\mysql\bin目录,设置root的新mysql数据库密码
  c:\mysql\bin>mysqladmin -u root flush-privileges password "newpassword"
  c:\mysql\bin>mysqladmin -u root -p shutdown
  将newpassword替为自己的新密码


顺其自然evo 2014-11-11 10:13
]]>
magento切换数据库,使用不同数据库http://www.blogjava.net/qileilove/archive/2014/11/10/419852.html顺其自然evo顺其自然evomon, 10 nov 2014 02:16:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/10/419852.htmlhttp://www.blogjava.net/qileilove/comments/419852.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/10/419852.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419852.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419852.html1. 在app/etc/local.xml 中,添加新的选项
false
1
mysql4
set names utf8
pdo_mysql
1
  2. 在需要使用的不同数据库的model resource中,重写 _setresource 方法,例如
class hello_vip_model_entity_vip_adapter extends mage_core_model_mysql4_abstract
{
protected $_logfile = 'vip.adapter.log';
protected function _construct()
{
$this->_setresource(array('read' =>'vip_space_read', 'write'
=>'vip_space_read'));
}
  经过以上两步,就能在某个model中使用不同的数据库


顺其自然evo 2014-11-10 10:16
]]>
java对存储过程的调用方法http://www.blogjava.net/qileilove/archive/2014/11/07/419644.html顺其自然evo顺其自然evofri, 07 nov 2014 02:29:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/07/419644.htmlhttp://www.blogjava.net/qileilove/comments/419644.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/07/419644.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419644.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419644.html 一、怎样实现对存储过程的调用:
  a:不带输出參数的
create procedure getsum
@n int =0<--此处为參数-->
as
declare @sum int<--定义变量-->
declare @i int
set @sum=0
set @i=0
while @i<=@n begin
set @sum=@sum @i
set @i=@i 1
end
print 'the sum is ' ltrim(rtrim(str(@sum)))
  在中运行:
  exec getsum 100
  在java中调用:
  java能够调用 可是在java程序却不能去显示该存储过程的结果 由于上面的存储过程的參数类型int 传递方式是in(按值)方式
import java.sql.*;
public class proceduretest
{
public static void main(string args[]) throws exception
{
//载入驱动
drivermanager.registerdriver(new sun.jdbc.odbc.jdbcodbcdriver());
//获得连接
connection conn=drivermanager.getconnection("jdbc:odbc:mydata","sa","");
//创建存储过程的对象
callablestatement c=conn.preparecall("{call getsum(?)}");
//给存储过程的參数设置值
c.setint(1,100); //将第一个參数的值设置成100
//运行存储过程
c.execute();
conn.close();
}
}
  b:带输出參数的
  1:返回int
alter procedure getsum
@n int =0,
@result int output
as
declare @sum int
declare @i int
set @sum=0
set @i=0
while @i<=@n begin
set @sum=@sum @i
set @i=@i 1
end
set @result=@sum
 在查询分析器中运行:
  declare @myresult int
  exec getsum 100,@myresult output
  print @myresult
  在java中调用:
import java.sql.*;
public class proceduretest
{
public static void main(string args[]) throws exception
{
//载入驱动
drivermanager.registerdriver(new sun.jdbc.odbc.jdbcodbcdriver());
//获得连接
connection conn=drivermanager.getconnection("jdbc:odbc:mydata","sa","");
//创建存储过程的对象
callablestatement c=conn.preparecall("{call getsum(?,?)}");
//给存储过程的第一个參数设置值
c.setint(1,100);
//注冊存储过程的第二个參数
c.registeroutparameter(2,java.sql.types.integer);
//运行存储过程
c.execute();
//得到存储过程的输出參数值
system.out.println (c.getint(2));
conn.close();
}
}
  2:返回varchar
  存储过程带游标:
  在存储过程中带游标 使用游标不停的遍历orderid
  create procedure cursorintoprocedure
  @pname varchar(8000) output
  as
  --定义游标
  declare cur cursor for select orderid from orders
  --定义一个变量来接收游标的值
  declare @v varchar(5)
  --打开游标
  open cur
  set @pname=''--给@pname初值
  --提取游标的值
  fetch next from cur into @v
  while @@fetch_status=0
  begin
  set @pname=@pname ';' @v
  fetch next from cur into @v
  end
  print @pname
  --关闭游标
  close cur
  --销毁游标
  deallocate cur
  运行存储过程:
  exec cursorintoprocedure ''
  java调用:
import java.sql.*;
public class proceduretest
{
public static void main(string args[]) throws exception
{
//载入驱动
drivermanager.registerdriver(new sun.jdbc.odbc.jdbcodbcdriver());
//获得连接
connection conn=drivermanager.getconnection("jdbc:odbc:mydata","sa","");
callablestatement c=conn.preparecall("{call cursorintoprocedure(?)}");
c.registeroutparameter(1,java.sql.types.varchar);
c.execute();
system.out.println (c.getstring(1));
conn.close();
}
}
  c:删除数据的存储过程
  存储过程:
drop table 学生基本信息表
create table 学生基本信息表
(
stuid int primary key,
stuname varchar(10),
stuaddress varchar(20)
)
insert into 学生基本信息表 values(1,'三毛','wuhan')
insert into 学生基本信息表 values(2,'三毛','wuhan')
create table 学生成绩表
(
stuid int,
chinese int,
pyhsics int
foreign key(stuid) references 学生基本信息表(stuid)
on delete cascade
on update cascade
)
insert into 学生成绩表 values(1,99,100)
insert into 学生成绩表 values(2,99,100)
  创建存储过程:
  create procedure delepro
  @stuid int
  as
  delete from 学生基本信息表 where stuid=@stuid
  --创建完成
  exec delepro 1 --运行存储过程
  --创建存储过程
  create procedure selepro
  as
  select * from 学生基本信息表
  --创建完成
  exec selepro --运行存储过程
  在java中调用:
import java.sql.*;
public class proceduretest
{
public static void main(string args[]) throws exception
{
//载入驱动
drivermanager.registerdriver(new sun.jdbc.odbc.jdbcodbcdriver());
//获得连接
connection conn=drivermanager.getconnection("jdbc:odbc:mydata","sa","");
//创建存储过程的对象
callablestatement c=conn.preparecall("{call delepro(?)}");
c.setint(1,1);
c.execute();
c=conn.preparecall("{call selepro}");
resultset rs=c.executequery();
while(rs.next())
{
string stu=rs.getstring("stuid");
string name=rs.getstring("stuname");
string add=rs.getstring("stuaddress");
system.out.println ("学号:" " " "姓名:" " " "地址");
system.out.println (stu " " name " " add);
}
c.close();
}
}
d:改动数据的存储过程
  创建存储过程:
  create procedure modpro
  @stuid int,
  @stuname varchar(10)
  as
  update 学生基本信息表 set stuname=@stuname where stuid=@stuid
  运行存储过程:
  exec modpro 2,'四毛'
  java调用存储过程:
import java.sql.*;
public class proceduretest
{
public static void main(string args[]) throws exception
{
//载入驱动
drivermanager.registerdriver(new sun.jdbc.odbc.jdbcodbcdriver());
//获得连接
connection conn=drivermanager.getconnection("jdbc:odbc:mydata","sa","");
//创建存储过程的对象
callablestatement c=conn.preparecall("{call modpro(?,?)}");
c.setint(1,2);
c.setstring(2,"美女");
c.execute();
c=conn.preparecall("{call selepro}");
resultset rs=c.executequery();
while(rs.next())
{
string stu=rs.getstring("stuid");
string name=rs.getstring("stuname");
string add=rs.getstring("stuaddress");
system.out.println ("学号:" " " "姓名:" " " "地址");
system.out.println (stu " " name " " add);
}
c.close();
}
}
  e:查询数据的存储过程(模糊查询)
  存储过程:
  create procedure findcusts
  @cust varchar(10)
  as
  select customerid from orders where customerid
  like '%' @cust '%'
  运行:
  execute findcusts 'alfki'
  在java中调用:
import java.sql.*;
public class proceduretest
{
public static void main(string args[]) throws exception
{
//载入驱动
drivermanager.registerdriver(new sun.jdbc.odbc.jdbcodbcdriver());
//获得连接
connection conn=drivermanager.getconnection("jdbc:odbc:mydata","sa","");
//创建存储过程的对象
callablestatement c=conn.preparecall("{call findcusts(?)}");
c.setstring(1,"tom");
resultset rs=c.executequery();
while(rs.next())
{
string cust=rs.getstring("customerid");
system.out.println (cust);
}
c.close();
}
}
  f:添加数据的存储过程
  存储过程:
  create procedure insertpro
  @stuid int,
  @stuname varchar(10),
  @stuaddress varchar(20)
  as
  insert into 学生基本信息表 values(@stuid,@stuname,@stuaddress)
  调用存储过程:
  exec insertpro 5,'555','555'
  在java中运行:
import java.sql.*;
public class proceduretest
{
public static void main(string args[]) throws exception
{
//载入驱动
drivermanager.registerdriver(new sun.jdbc.odbc.jdbcodbcdriver());
//获得连接
connection conn=drivermanager.getconnection("jdbc:odbc:mydata","sa","");
//创建存储过程的对象
callablestatement c=conn.preparecall("{call insertpro(?,?,?)}");
c.setint(1,6);
c.setstring(2,"liu");
c.setstring(3,"wuhan");
c.execute();
c=conn.preparecall("{call selepro}");
resultset rs=c.executequery();
while(rs.next())
{
string stuid=rs.getstring("stuid");
string name=rs.getstring("stuname");
string address=rs.getstring("stuaddress");
system.out.println (stuid " " name " " address);
}
c.close();
}
}
  g:在java中创建存储过程 而且在java中直接调用
import java.sql.*;
public class proceduretest
{
public static void main(string args[]) throws exception
{
//载入驱动
drivermanager.registerdriver(new sun.jdbc.odbc.jdbcodbcdriver());
//获得连接
connection conn=drivermanager.getconnection("jdbc:odbc:mydata","sa","");
statement stmt=conn.createstatement();
//在java中创建存储过程
stmt.executeupdate("create procedure oop as select * from 学生成绩表");
callablestatement c=conn.preparecall("{call oop}");
resultset rs=c.executequery();
while(rs.next())
{
string chinese=rs.getstring("chinese");
system.out.println (chinese);
}
conn.close();
}
}


顺其自然evo 2014-11-07 10:29
]]>
鸟瞰数据库系统原理http://www.blogjava.net/qileilove/archive/2014/11/03/419423.html顺其自然evo顺其自然evomon, 03 nov 2014 01:30:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/03/419423.htmlhttp://www.blogjava.net/qileilove/comments/419423.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/03/419423.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419423.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419423.html
  系统是一种管理数据的系统,首先设计到数据,谈到数据就要从数据管理的历史来看数据库系统的发展。其中,达到数据库阶段后,我们开始来讨论我们这门课程。
  先来看应用部分:
  1、分析数据
  设计使用数据库,首先要对问题进行分析。那么数据库世界中的问题不就围绕数据开展的嘛!所以先从数据开始分析。
  数据分析时,由于人们往往不能对问题的解决一步到位。所以人们对数据库的分析也是一般从宏观到微观,采用抽象的办法来对数据进行逐步细化的分析。人们在对数据抽象过程中对数据抽象不同阶段得到四种模型。
  由于人们在得到四种模型过程中是通过不断细化得到的,所以这些模型也自然形成了一种层次关系。这种层次关系各自解决不同层次的问题,层次之间通过映射来联系。这种数据库结构分析好之后就该动手设计了。
  2、设计数据库
  要设计数据库,先整体规划好,然后弄清楚需求。有了一个比较清晰的需求,下面针对各个模型进行具体的设计。
  在概念模型设计中,一个比较重要的工具是e-r图,通过e-r图可以比较直观地了解将要开发的系统。如果一个好的系统设计出来,那么自然要上手尝试一下它的魅力。
  3、使用
  数据库的使用最基本的是语言,单独来说sql语言其实就是对表的增删改查。而对sql语言扩充之后的t-sql也就是增加了一些流程控制。数据库语言的使用学会之后,就要学会对数据库的管理了。
  4、管理
  使用数据库系统的前提是该系统能保证数据的正确性和安全性,要能保证这些离不开对数据库系统的管理。数据正确性最直接的是使用约束,限制数据范围。其次是通过事务机制来保证随着系统运行,数据不会发生意外损失。系统中多个事务并行进行,就要对系统进行并行控制。最后最糟糕的情况,就一定能保证恢复原来的状态。
  保证了数据的正确性仍然不能满足人们的需要,因为对数据的操作是有权限的,正如我们在程序设计中使用访问控制符来限定对数据操作一样。我们要对数据的安全进行管理,防止非法的操作及意外故障对系统的破坏。
  再看理论部分:
  应用总是要有相应的理论来支持和指导的,这里我们按照顺序从建表的理论开始,在表设计中总要有个好坏的标准吧,盲目地建表会产生许多麻烦的问题,这就提出了范式。建表有了统一的标准后,接下来就是用表了即操作表,对表有许多的操作,你讲不出为什么能这么做总不行吧。所以下面就针对表的操作来研究这些操作的理论。


顺其自然evo 2014-11-03 09:30
]]>
sql server数据库状态监控 - 错误日志http://www.blogjava.net/qileilove/archive/2014/10/30/419266.html顺其自然evo顺其自然evothu, 30 oct 2014 04:01:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/30/419266.htmlhttp://www.blogjava.net/qileilove/comments/419266.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/30/419266.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419266.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419266.html 无论是 (unix 或者),还是应用程序 (web 服务,系统等等) ,通常都有自身的日志机制,以便故障时追溯现场及原因。windows event log和   error log就是这样的日志, ps: sql server 中的错误日志 (error log) 类似于 中的alert 文件。
  一. 错误日志简介
  1. windows事件日志与sql server 错误日志
  windows事件日志中,应用程序里的sql server和sql server agent服务,分别对应来源自mssqlserver和sqlserveragent的日志信息;
  sql server错误日志中信息,与windows事件日志里来源自mssqlserver的日志信息基本一致,不同的是,windows事件日志里信息为应用程序级,较为简洁些,而sql server错误日志里通常有具体的数据库错误信息。比如:
  windows事件日志中错误信息:
  login failed for user 'sa'. reason: password did not match that for the login provided. [client: 10.213.20.8]
  sql server错误日志中错误信息:
  login failed for user 'sa'. reason: password did not match that for the login provided. [client: 10.213.20.8]
  error: 18456, severity: 14, state: 8.
  2. 如何理解sql server的error message?
  以上面的error: 18456, severity: 14, state: 8.为例:
  (1) error,错误编号,可以在系统表里查到对应的文本信息;
  select * from sys.messages where message_id = 18456
  (2) severity,错误级别,表明这个错误的严重性,一共有25个等级,级别越高,就越需要我们去注意处理,20~25级别的错误会直接报错并跳出执行,用sql语句的try…catch是捕获不到的;
  (3) state,错误状态,比如18456错误,帮助文档记载了如下状态,不同状态代表不同错误原因:
  1. error information is not available. this state usually means you do not have permission to receive the error details. contact your sql server administrator for more information.
  2.  user id is not valid.
  5.  user id is not valid.
  6.  an attempt was made to use a windows login name with sql server authentication.
  7.  login is disabled, and the password is incorrect.
  8.  the password is incorrect.
  9.  password is not valid.
  11. login is valid, but server access failed.
  12. login is valid login, but server access failed.
  18. password must be changed.
  还有文档未记载的state: 10, state: 16,通常是sql server启动帐号权限问题,或者重启sql server服务就好了。
  3. sql server 错误日志包含哪些信息
  sql server错误日志中包含sql server开启、运行、终止整个过程的:运行环境信息、重要操作、级别比较高的错误等:
  (1)  sql server/windows基本信息,如:版本、进程号、ip/主机名、端口、cpu个数等;
  (2) sql server启动参数及认证模式、内存分配;
  (3) sql server实例下每个数据打开状态(包括系统和用户数据库);
  (4) 数据库或服务器配置选项变更,kill操作,开关dbcc跟踪,登录失败等等
  (5) 数据库备份/还原的记录;
  (6) 内存相关的错误和警告,可能会dump很多信息在错误日志里;
  (7) sql server调度异常警告、io操作延迟警告、内部访问越界 (也就是下面说到的error 0);
  (8) 数据库损坏的相关错误,以及dbcc checkdb的结果;
  (9) 实例关闭时间;
  另外,可以手动开关一些跟踪标记(trace flags),来自定义错误日志的内容,比如:记录如用户登入登出记录(login auditing),查询的编译执行等信息,比较常用的可能是用于检查死锁时的1204/1222 跟踪标记。
  通常错误日志不会记录sql语句的性能问题,如:阻塞、超时的信息,也不会记录windows层面的异常(这会在windows事件日志中记载)。
  sql server agent错误日志中同样也包括:信息/警告/错误这几类日志,但要简单很多。
4. sql server 错误日志存放在哪里
  假设sql server被安装在x:\program files\microsoft sql server,则sql server 与sql server agent的错误日志文件默认被放在:
  x:\program files\microsoft sql server\mssql.n\mssql\log\ errorlog ~ errorlog.n
  x:\program files\microsoft sql server\mssql.n\mssql\log\sqlagent.n and sqlagent.out.
  如果错误日志路径被管理员修改,可以通过以下某种方式找到:
  (1) 操作系统的应用程序日志里,sql server启动时会留下错误日志文件的路径;
  (2) 通过ssms/管理/错误日志,sql server启动时会留下错误日志文件的路径;
  (3) sql server配置管理器里,点击sql server实例/属性/高级/启动参数 (startup parameters) ;
  (4) 通过一个未记载的sql语句 (在sql server 2000中测试无效,2005及以后可以):
  select serverproperty('errorlogfilename')
  5. sql server 错误日志目录下的其他文件
  在错误日志目录下除了sql server和sql server agent的日志,可能还会有以下文件:
  (1) 维护计划产生的report文件 (sql server 2000的时候,后来的维护计划log记录在msdb);
  (2) 默认跟踪(default trace) 生成的trace文件,ps: 审计(audit) 产生的trace文件在\mssql\data下;
  (3) 全文索引的错误、日志文件;
  (4) sqldump文件,比如:exception.log/sqldump0001.txt/sqldump0001.mdmp,大多是发生error 0时dump出来的,同时在错误日志里通常会有类似如下记录:
  error: 0, severity: 19, state: 0
  sqldumpexceptionhandler: process 232 generated fatal exception c0000005 exception_access_violation. sql server is terminating this process.
  顺便说下error 0 的解释:
  you've hit a bug of some kind - an access violation is an unexpected condition. you need to contact product support (http://support.microsoft.com/sql) to help figure out what happened and whether there's a fix available.
  is your server up to date with service packs? if not, you might try updating to the latest build. this error is an internal error in sql server. if you are up to date, you should report it to ms.
  二. 错误日志维护
  1. 错误日志文件个数
  1.1 sql server错误日志
  sql server错误日志文件数量默认为7个:1个正在用的(errorlog)和6个归档的(errorlog.1 – errorlog.6),可以配置以保留更多(最多99个);
  (1) 打开到ssms/管理/sql server logs文件夹/右击/配置;
  (2) 通过未记载的扩展存储过程,直接读写注册表也行:
  use [master]
  go
  exec xp_instance_regwrite n'hkey_local_machine', n'software\microsoft\mssqlserver\mssqlserver', n'numerrorlogs', reg_dword, 50
  go
  --check current errorlog amout
  use [master]
  go
  declare @i int
  exec xp_instance_regread n'hkey_local_machine', n'software\microsoft\mssqlserver\mssqlserver', n'numerrorlogs', @i output
  select @i
  sql server作为一个windows下的应用程序,很多信息是写在注册表里的,自然也可以手动打开注册表编辑器或写shell去修改注册表来作配置。
  最后,可以通过 如下sql语句查看已存在的错误日志编号、起止时间、当前大小。
  exec master..xp_enumerrorlogs
  1.2 sql server agent错误日志
  sql server agent错误日志文件数量共为10个:1个正在用的(sqlagent.out),9个归档的(sqlagent.1 - sqlagent.9),个数不可以修改,但可以配置日志所记载的信息类型:信息、警告、错误。
  (1) 打开到ssms/sql server agent/error logs文件夹/右击/配置;
  (2) 未记载的扩展存储过程:
  use [msdb]
  go
  exec msdb.dbo.sp_set_sqlagent_properties @errorlogging_level=7
  go
  至于@errorlogging_level各个值的意思,由于没有文档记载,需要自己测试并推算下。
  2. 错误日志文件归档
  2.1 为什么要归档错误日志?
  假设sql server实例从来没被重启过,也没有手动归档过错误日志,那么错误日志文件可能会变得很大,尤其是有内部错误时会dump很多信息,一来占空间,更重要的是:想要查看分析也会不太方便。
  sql server/sql server agent 错误日志有2种归档方式,即:创建一个新的日志文件,并将最老的日志删除。
  (1) 自动归档:在sql server/ sql server agent服务重启时;
  (2) 手动归档:定期运行如下系统存储过程
  exec master..sp_cycle_errorlog; --dbcc errorlog 亦可
  exec msdb.dbo.sp_cycle_agent_errorlog;--sql agent 服务需在启动状态下才有效
  2.2 可不可以根据文件大小来归档?
  可能有人会觉得,虽然很久没归档,但是错误日志确实不大,没必要定期归档,最好可以根据文件大小来判断。有以下几种方法:
  (1) 有些监控工具,比如:sql diagnostic manager,就有检测错误日志文件大小,并根据大小来决定是否归档的功能;
  (2) 自定义脚本也可以,比如:powershell, xp_enumerrorlogs 都可以检查错误日志大小;
  (3) sql server 2012支持一个注册表选项,以下语句限制每个错误日志文件为5m,到了5m就会自动归档,在2008/2008 r2测试无效:
  use [master]
  go
  exec xp_instance_regwrite n'hkey_local_machine', n'software\microsoft\mssqlserver\mssqlserver', n'errorlogsizeinkb', reg_dword, 5120;
三. 错误日志查看及告警
  错误日志以文本方式记录,记事本就可以查看,如果错误日志很大,可以选择gvim/ultraedit /dos窗口type errorlog等,这些方式都会“分页”加载,不会卡住。
  1. 错误日志查看
  sql server提供了以下2种方式查看:
  (1) 日志查看器 (log viewer),除了可以查看sql server 与sql server agent的错误日志,还可以查看操作系统日志、数据库邮件日志。不过当日志文件太大时,图形界面非常慢;
  (2) 未记载的扩展存储过程xp_readerrorlog,另外还有一个名为sp_readerrorlog的存储过程,它是对xp_readerrorlog的简单封装,并且只提供了4个参数,直接使用xp_readerrorlog即可:
  在sql server 2000里,仅支持一个参数,即错误日志号,默认为0~6:
exec dbo.xp_readerrorlog   --写0或null都会报错,直接运行即可
exec dbo.xp_readerrorlog 1
exec dbo.xp_readerrorlog 6
--sql server 2000 read error log
if object_id('tempdb..#tmp_error_log_all') is not null
drop table #tmp_error_log_all
create table #tmp_error_log_all
(
info varchar(8000),--datetime processinfo text
num  int
)
insert into #tmp_error_log_all
exec dbo.xp_readerrorlog
--split error text
if object_id('tempdb..#tmp_error_log_split') is not null
drop table #tmp_error_log_split
create table #tmp_error_log_split
(
logdate      datetime,--datetime
processinfo  varchar(100),--processinfo
info         varchar(7900)--text
)
insert into #tmp_error_log_split
select convert(datetime,left(info,22),120),
left(stuff(info,1,23,''),charindex(' ',stuff(info,1,23,'')) - 1),
ltrim(stuff(info,1,23 charindex(' ',stuff(info,1,23,'')),''))
from #tmp_error_log_all
where isnumeric(left(info,4)) = 1
and info <> '.'
and substring(info,11,1) = ' '
select *
from #tmp_error_log_split
where info like '456%'
  在sql server 2005及以后版本里,支持多达7个参数,说明如下:
  exec dbo.xp_readerrorlog 1,1,n'string1',n'string2',null,null,n'desc'
  参数1.日志文件号: 0 = 当前, 1 = archive #1, 2 = archive #2, etc...
  参数2.日志文件类型:  1 or null = sql server 错误日志, 2 = sql agent 错误日志
  参数3.检索字符串1: 用来检索的字符串
  参数4.检索字符串2:  在检索字符串1的返回结果之上再做过滤
  参数5.日志开始时间
  参数6.日志结束时间
  参数7.结果排序: n'asc' = 升序, n'desc' = 降序
--sql server 2005 read error log
if object_id('tempdb..#tmp_error_log') is not null
drop table #tmp_error_log
create table #tmp_error_log
(
logdate      datetime,
processinfo  varchar(100),
info         varchar(8000)
)
insert into #tmp_error_log
exec dbo.xp_readerrorlog
select *
from #tmp_error_log
where info like '456%'
  2. 错误日志告警
  可以通过对某些关键字做检索:错误(error),警告(warn),失败(fail),停止(stop),而进行告警 (database mail),以下脚本检索24小时内的错误日志:
declare
@start_time    datetime
,@end_time      datetime
set @start_time = convert(char(10),getdate() - 1,120)
set @end_time = getdate()
if object_id('tempdb..#tmp_error_log') is not null
drop table #tmp_error_log
create table #tmp_error_log
(
logdate      datetime,
processinfo  varchar(100),
info         varchar(8000)
)
insert into #tmp_error_log
exec dbo.xp_readerrorlog 0,1,null,null,@start_time,@end_time,n'desc'
select count(1) as num, max(logdate) as logdate,info
from #tmp_error_log
where (info like '%error%'
or info like '%warn%'
or info like '�il%'
or info like '%stop%')
and info not like '%checkdb%'
and info not like '%registry startup parameters%'
and info not like '%logging sql server messages in file%'
and info not like '%previous log for older entries%'
group by info
  当然,还可以添加更多关键字:kill, dead, victim, cannot, could, not, terminate, bypass, roll, truncate, upgrade, recover, io requests taking longer than,但当中有个例外,就是dbcc checkdb,它的运行结果中必然包括error字样,如下:
  dbcc checkdb (xxxx) executed by sqladmin found 0 errors and repaired 0 errors.
  所以对0 errors要跳过,只有在发现非0 errors时才作告警。
  小结
  如果没有监控工具,那么可选择扩展存储过程,结合数据库邮件的方式,作自动检查及告警,并定期归档错误日志文件以避免文件太大。大致步骤如下 :
  (1) 部署数据库邮件;
  (2) 部署作业:定时检查日志文件,如检索到关键字,发邮件告警;
  (3) 部署作业:定期归档错误日志,可与步骤(2) 合并作为两个step放在一个作业里。


顺其自然evo 2014-10-30 12:01
]]>
磁盘读写与数据库的关系http://www.blogjava.net/qileilove/archive/2014/10/30/419265.html顺其自然evo顺其自然evothu, 30 oct 2014 04:00:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/30/419265.htmlhttp://www.blogjava.net/qileilove/comments/419265.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/30/419265.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419265.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419265.html 一 磁盘物理结构
  (1) 盘片:硬盘的盘体由多个盘片叠在一起构成。
  在硬盘出厂时,由硬盘生产商完成了低级格式化(物理格式化),作用是将空白的盘片(platter)划分为一个个同圆心、不同半径的磁道(track),还将磁道划分为若干个扇区(sector),每个扇区可存储128×2的n次方(n=0.1.2.3)字节信息,默认每个扇区的大小为512字节。通常使用者无需再进行低级格式化操作。
  (2) 磁头:每张盘片的正反两面各有一个磁头。
  (3) 主轴:所有盘片都由主轴电机带动旋转。
  (4) 控制集成电路板:复杂!上面还有rom(内有软件系统)、cache等。
  二 磁盘如何完成单次io操作
  (1) 寻道
  当控制器对磁盘发出一个io操作命令的时候,磁盘的驱动臂(actuator arm)带动磁头(head)离开着陆区(landing zone,位于内圈没有数据的区域),到要操作的初始数据块所在的磁道(track)的正上方,这个过程被称为寻道(seeking),对应消耗的时间被称为寻道时间(seek time);
  (2) 旋转延迟
  找到对应磁道还不能马上读取数据,这时候磁头要等到磁盘盘片(platter)旋转到初始数据块所在的扇区(sector)落在读写磁头正下方之后才能开始读取数据,在这个等待盘片旋转到可操作扇区的过程中消耗的时间称为旋转延时(rotational latency);
  (3) 数据传送
  接下来就随着盘片的旋转,磁头不断的读/写相应的数据块,直到完成这次io所需要操作的全部数据,这个过程称为数据传送(data transfer),对应的时间称为传送时间(transfer time)。完成这三个步骤之后单次io操作也就完成了。
  根据磁盘单次io操作的过程,可以发现:
  单次io时间 = 寻道时间 旋转延迟 传送时间
  进而推算iops(io per second)的公式为:
  iops = 1000ms/单次io时间
 三 磁盘iops计算
  不同磁盘,它的寻道时间,旋转延迟,数据传送所需的时间各是多少?
  1. 寻道时间
  考虑到被读写的数据可能在磁盘的任意一个磁道,既有可能在磁盘的最内圈(寻道时间最短),也可能在磁盘的最外圈(寻道时间最长),所以在计算中我们只考虑平均寻道时间。
  在购买磁盘时,该参数都有标明,目前的sata/sas磁盘,按转速不同,寻道时间不同,不过通常都在10ms以下:
  2. 旋转延时
  和寻道一样,当磁头定位到磁道之后有可能正好在要读写扇区之上,这时候是不需要额外的延时就可以立刻读写到数据,但是最坏的情况确实要磁盘旋转整整一圈之后磁头才能读取到数据,所以这里也考虑的是平均旋转延时,对于15000rpm的磁盘就是(60s/15000)*(1/2) = 2ms。
  3. 传送时间
  (1) 磁盘传输速率
  磁盘传输速率分两种:内部传输速率(internal transfer rate),外部传输速率(external transfer rate)。
  内部传输速率(internal transfer rate),是指磁头与硬盘缓存之间的数据传输速率,简单的说就是硬盘磁头将数据从盘片上读取出来,然后存储在缓存内的速度。
  理想的内部传输速率不存在寻道,旋转延时,就一直在同一个磁道上读数据并传到缓存,显然这是不可能的,因为单个磁道的存储空间是有限的;
  实际的内部传输速率包含了寻道和旋转延时,目前家用磁盘,稳定的内部传输速率一般在30mb/s到45mb/s之间(服务器磁盘,应该会更高)。
  外部传输速率(external transfer rate),是指硬盘缓存和系统总线之间的数据传输速率,也就是计算机通过硬盘接口从缓存中将数据读出交给相应的硬盘控制器的速率。
  硬盘厂商在硬盘参数中,通常也会给出一个最大传输速率,比如现在sata3.0的6gbit/s,换算一下就是6*1024/8,768mb/s,通常指的是硬盘接口对外的最大传输速率,当然实际使用中是达不到这个值的。
  这里计算iops,保守选择实际内部传输速率,以40m/s为例。
  (2) 单次io操作的大小
  有了传送速率,还要知道单次io操作的大小(io chunk size),才可以算出单次io的传送时间。那么磁盘单次io的大小是多少?答案是:不确定。
  操作系统为了提高 io的性能而引入了文件系统缓存(file system cache),系统会根据请求数据的情况将多个来自io的请求先放在缓存里面,然后再一次性的提交给磁盘,也就是说对于数据库发出的多个8k数据块的读操作有可能放在一个磁盘读io里就处理了。
  还有,有些存储系统也是提供了缓存(cache),接收到操作系统的io请求之后也是会将多个操作系统的 io请求合并成一个来处理。
  不管是操作系统层面的缓存,还是磁盘控制器层面的缓存,目的都只有一个,提高数据读写的效率。因此每次单独的io操作大小都是不一样的,它主要取决于系统对于数据读写效率的判断。这里以sql server数据库的数据页大小为例:8k。
  (3) 传送时间
  传送时间 = io chunk size/internal transfer rate = 8k/40m/s = 0.2ms
  可以发现:
  (3.1) 如果io chunk size大的话,传送时间会变长,单次io时间就也变长,从而导致iops变小;
  (3.2) 机械磁盘的主要读写成本,都花在了寻址时间上,即:寻道时间 旋转延迟,也就是磁盘臂的摆动,和磁盘的旋转延迟。
  (3.3) 如果粗略的计算iops,可以忽略传送时间,1000ms/(寻道时间 旋转延迟)即可。
  4. iops计算示例
  以15000rpm为例:
  (1) 单次io时间
  单次io时间 = 寻道时间 旋转延迟 传送时间 = 3ms 2ms 0.2 ms = 5.2 ms
  (2) iops
  iops = 1000ms/单次io时间 = 1000ms/5.2ms = 192 (次)
  这里计算的是单块磁盘的随机访问iops。
  考虑一种极端的情况,如果磁盘全部为顺序访问,那么就可以忽略:寻道时间 旋转延迟 的时长,iops的计算公式就变为:iops = 1000ms/传送时间
  iops = 1000ms/传送时间= 1000ms/0.2ms = 5000 (次)
  显然这种极端的情况太过理想,毕竟每个磁道的空间是有限的,寻道时间 旋转延迟 时长确实可以减少,不过是无法完全避免的。
  四 数据库中的磁盘读写
  1. 随机访问和连续访问
  (1) 随机访问(random access)
  指的是本次io所给出的扇区地址和上次io给出扇区地址相差比较大,这样的话磁头在两次io操作之间需要作比较大的移动动作才能重新开始读/写数据。
  (2) 连续访问(sequential access)
  相反的,如果当次io给出的扇区地址与上次io结束的扇区地址一致或者是接近的话,那磁头就能很快的开始这次io操作,这样的多个io操作称为连续访问。
  (3) 以sql server数据库为例
  数据文件,sql server统一区上的对象,是以extent(8*8k)为单位进行空间分配的,数据存放是很随机的,哪个数据页有空间,就写在哪里,除非通过文件组给每个表预分配足够大的、单独使用的文件,否则不能保证数据的连续性,通常为随机访问。
  另外哪怕聚集索引表,也只是逻辑上的连续,并不是物理上。
  日志文件,由于有vlf的存在,日志的读写理论上为连续访问,但如果日志文件设置为自动增长,且增量不大,vlf就会很多很小,那么就也并不是严格的连续访问了。
  2. 顺序io和并发io
  (1) 顺序io模式(queue mode)
  磁盘控制器可能会一次对磁盘组发出一连串的io命令,如果磁盘组一次只能执行一个io命令,称为顺序io;
  (2) 并发io模式(burst mode)
  当磁盘组能同时执行多个io命令时,称为并发io。并发io只能发生在由多个磁盘组成的磁盘组上,单块磁盘只能一次处理一个io命令。
  (3) 以sql server数据库为例
  有的时候,尽管磁盘的iops(disk transfers/sec)还没有太大,但是发现数据库出现io等待,为什么?通常是因为有了磁盘请求队列,有过多的io请求堆积。
  磁盘的请求队列和繁忙程度,通过以下性能计数器查看:
  logicaldisk/avg.disk queue length
  logicaldisk/current disk queue length
  logicaldisk/%disk time
  这种情况下,可以做的是:
  (1) 简化业务逻辑,减少io请求数;
  (2) 同一个实例下的多个用户数据库,迁移到不同实例下;
  (3) 同一个数据库的日志、数据文件,分离到不同的存储单元;
  (4) 借助ha策略,做读写操作的分离。
  3. iops和吞吐量(throughput)
  (1) iops
  iops即每秒进行读写(i/o)操作的次数。在计算传送时间时,有提到:如果io chunk size大的话,那么iops会变小,假设以100m为单位读写数据,那么iops就会很小。
  (2) 吞吐量(throughput)
  吞吐量指每秒可以读写的字节数。同样假设以100m为单位读写数据,尽管iops很小,但是每秒读写了n*100m的数据,吞吐量并不小。
  (3) 以sql server数据库为例
  对于oltp的系统,经常读写小块数据,多为随机访问,用iops来衡量读写性能;
  对于数据仓库,日志文件,经常读写大块数据,多为顺序访问,用吞吐量来衡量读写性能。
  磁盘当前的iops,通过以下性能计数器查看:
  logicaldisk/disk transfers/sec
  logicaldisk/disk reads/sec
  logicaldisk/disk writes/sec
  磁盘当前的吞吐量,通过以下性能计数器查看:
  logicaldisk/disk bytes/sec
  logicaldisk/disk read bytes/sec
  logicaldisk/disk write bytes/sec


顺其自然evo 2014-10-30 12:00
]]>
为mysql选择合适的备份方式http://www.blogjava.net/qileilove/archive/2014/10/30/419262.html顺其自然evo顺其自然evothu, 30 oct 2014 03:58:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/30/419262.htmlhttp://www.blogjava.net/qileilove/comments/419262.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/30/419262.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419262.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419262.html 的备份是极其重要的事情。如果没有备份,遇到下列情况就会抓狂:
  update or delete whitout where…
  table was dropped accidentally…
  innodb was corrupt…
  entire datacenter loses power…
  从数据安全的角度来说,服务器磁盘都会做raid,本身也有主从、drbd等容灾机制,但它们都无法完全取代备份。容灾和高可用能帮我们有效的应对物理的、硬件的、机械的故障,而对我们犯下的逻辑错误却无能为力。每一种逻辑错误发生的概率都极低,但是当多种可能性叠加的时候,小概率事件就放大成很大的安全隐患,这时候备份的必要性就凸显了。那么在众多的mysql备份方式中,哪一种才是适合我们的呢?
  常见的备份方式
  mysql本身为我们提供了mysqldump、mysqlbinlog远程备份工具,percona也为我们提供了强大的xtrabackup,加上开源的mydumper,还有基于主从同步的延迟备份、从库冷备等方式,以及基于文件系统快照的备份,其实选择已经多到眼花缭乱。而备份本身是为了恢复,所以能够让我们在出现故障后迅速、准确恢复的备份方式,就是最适合我们的,当然,同时能够省钱、省事,那就非常完美。下面就我理解的几种备份工具进行一些比较,探讨下它们各自的适用场景。
  1. mysqldump & mydumper
  mysqldump是最简单的逻辑备份方式。在备份myisam表的时候,如果要得到一致的数据,就需要锁表,简单而粗暴。而在备份innodb表的时候,加上–master-data=1 –single-transaction 选项,在事务开始时刻,记录下binlog pos点,然后利用mvcc来获取一致的数据,由于是一个长事务,在写入和更新量很大的数据库上,将产生非常多的undo,显著影响性能,所以要慎用。
  优点:简单,可针对单表备份,在全量导出表结构的时候尤其有用。
  缺点:简单粗暴,单线程,备份慢而且恢复慢,跨idc有可能遇到时区问题。
  mydumper是mysqldump的加强版。相比mysqldump:
  内置支持压缩,可以节省2-4倍的存储空间。
  支持并行备份和恢复,因此速度比mysqldump快很多,但是由于是逻辑备份,仍不是很快。
  2. 基于文件系统的快照
  基于文件系统的快照,是物理备份的一种。在备份前需要进行一些复杂的设置,在备份开始时刻获得快照并记录下binlog pos点,然后采用类似copy-on-write的方式,把快照进行转储。转储快照本身会消耗一定的io资源,而且在写入压力较大的实例上,保存被更改数据块的前印象也会消耗io,最终表现为整体性能的下降。而且服务器还要为copy-on-write快照预留较多的磁盘空间,这本身对资源也是一种浪费。因此这种备份方式我们使用的不多。
  由于mysql中不可避免的含有myisam表,同时innobackup并不备份表结构等文件,因此想要完整的备份mysql实例,就少不了要执行flush tables with read lock,而这个语句会被任何查询(包括select)阻塞,在阻塞过程中,它又反过来阻塞任何查询(包括select)。如果碰巧备份实例上有长查询先于flush tables with read lock执行,数据库就会hang住。而当flush tables with read lock获得全局锁后,虽然查询可以执行,但是仍会阻塞更新,所以,我们希望flush tables with read lock从发起到结束,持续的时间越短越好。
  为了解决这个问题,有两种比较有效的方法:
  1. 尽量不用myisam表。
  2. xtrabackup增加了–rsync选项,通过两次rsync来减少持有全局锁的时间。
  优化后的备份过程如下:
  优点:在线热备,全备 增备 流备,支持限速,支持压缩,支持加密。
  缺点:需要获取全局锁,如果遇到长查询,等待时间将不可控,因此要做好监控,必要时杀死长查询或自杀;遇到超大的实例,备份过程较长,redo log太大会影响恢复速度,这种情况下最好采用延迟备份。
  4. mysqlbinlog 5.6
  上述所有的备份方式,都只能把数据库恢复到备份的某个时间点:mysqldump和mydumper,以及snapshot是备份开始的时间点;xtrabackup是备份结束的时间点。要想实现point in time的恢复,还必须备份binlog。同时binlog也是实现增备的宝贵资源。
  幸运的是,mysql 5.6为我们提供了远程备份binlog的选项:
  mysqlbinlog --raw --read-from-remote-server --stop-never
  它会伪装成mysql从库,从远程获取binlog然后进行转储。这对线上主库容量不够无法保存较多binlog的场景非常有用。但是,它毕竟不像真正的mysql从库实例,状态监控和同步都需要单独部署。因此个人觉得采用blackhole来备份全量的binlog是更好的选择。笔者曾经实现过一个自动搭建blackhole从库的工具,稍加修改,就可以完美搭建出blackhole从库。一旦同步起来,基本一劳永逸,很少出问题,主从切换的时候跟着切了就行。
  提示:
  不要小看binlog的备份。当5.6的多线程复制大规模使用后,从库追赶主库命令点的耗时将被极大缩短,这样我们把每天一次的全量备份改为每3天一次、甚至每周一次的全量备份,和持续的binlog增量备份。遇到故障需要恢复数据的时候,重放3、5天的binlog也是极快的。降低备份频率最直接的好处是,省钱、省事。
  blackhole对于备份binlog是极好的。一方面可以长久的备份binlog用于恢复数据库,另一方面,在其上配置半同步复制,可以有效防止主库的binlog丢失。
  总结
  备份方式各有千秋,而对我们来说,面对数千实例,选择合适的备份工具来实现统一配置、统一规划,构建智能调度的备份云平台才是王道。毕竟,多种备份方式共存的运维成本是不容忽视的。
  从使用经验来看,用xtrabackup全备数据,用blackhole增备binlog,并定期对备份数据的有效性进行验证,是当下比较好的选择。


顺其自然evo 2014-10-30 11:58
]]>
hibernate与数据库的触发器协同工作http://www.blogjava.net/qileilove/archive/2014/10/30/419261.html顺其自然evo顺其自然evothu, 30 oct 2014 03:57:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/30/419261.htmlhttp://www.blogjava.net/qileilove/comments/419261.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/30/419261.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419261.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419261.htmlhibernate 与中的触发器协同时, 会造成两类问题
  1、触发器使 session 的缓存中的持久化对象与数据库中对应的数据不一致:触发器运行在数据库中, 它执行的操作对 session 是透明的 session 的
  凯发天生赢家一触即发官网的解决方案: 在执行完 session 的相关操作后, 立即调用 session 的 flush() 和 refresh() 方法, 迫使 session 的缓存与数据库同步(refresh() 方法重新从数据库中加载对象)
  2、update() 方法盲目地激发触发器: 无论游离对象的属性是否发生变化, 都会执行 update 语句, 而 update 语句会激发数据库中相应的触发器
  凯发天生赢家一触即发官网的解决方案:在映射文件的的 元素中设置 select-before-update 属性: 当 session 的 update 或 saveorupdate() 方法更新一个游离对象时, 会先执行 select 语句, 获得当前游离对象在数据库中的最新数据, 只有在不一致的情况下才会执行 update 语句(没有用到触发器的时候一般的情况下最好不要设置,因为会降低效率的)


顺其自然evo 2014-10-30 11:57
]]>
web应用手工渗透测试—用sqlmap进行sql盲注测试http://www.blogjava.net/qileilove/archive/2014/10/30/419209.html顺其自然evo顺其自然evothu, 30 oct 2014 02:38:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/30/419209.htmlhttp://www.blogjava.net/qileilove/comments/419209.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/30/419209.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419209.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419209.html 简介
  本文主要关注注入,假设读者已经了解一般的sql注入技术,在我之前的中有过介绍,即通过输入不同的参数,等待服务器的反应,之后通过不同的前缀和后缀(suffix and prefix )注入到。本文将更进一步,讨论sql盲注,如果读者没有任何相关知识储备,建议先去wikipedia学习一下。在继续之前需要提醒一下,如果读者也想要按本文的步骤进行,需要在nowasp mutillidae环境搭建好之后先注册一个nowasp mutillidae帐号。
  sql注入前言
  本文演示从界面注入sql命令的方法,但不会直接连接到数据库,而是想办法使后端数据库处理程序将我们的查询语句当作sql命令去执行。本文先描述一些注入基础知识,之后讲解盲注的相关内容。
  show time
  这里我以用户名“jonnybravo”和密码“momma”登录,之后进入用户查看页面,位于owasp 2013 > a1 sql injection > extract data > user info。要查看用户信息,需要输入用户id与密码登录,之后就可以看到当前用户的信息了。
  如我之前的文章所提到的那样,这个页面包含sql注入漏洞,所以我会尝试各种注入方法来操纵数据库,需要使用我之前文章提到的后缀(suffix)与前缀(prefix)的混合。这里我使用的注入语句如下:
  username: jonnybravo’ or 1=1; –
  该注入语句要做的就是从数据库查询用户jonnybravo,获取数据后立刻终止查询(利用单引号),之后紧接着一条or语句,由于这是一条“if状态”查询语句,而且这里给出 “or 1=1”,表示该查询永远为真。1=1表示获取数据库中的所有记录,之后的;–表示结束查询,告诉数据库当前语句后面没有其它查询语句了。
  
图1 正常方式查看用户信息
  将payload注入后,服务器泄露了数据库中的所有用户信息。如图2所示:
  
图2 注入payload导致数据库中所有数据泄露
  至此,本文向读者演示了一种基本sql注入,下面笔者用backtrack和samurai 等渗透发行版中自带的sqlmap工具向读者演示。要使用sqlmap,只需要打开终端,输入sqlmap并回车,如下图所示:
  如果读者首次使用sqlmap,不需要什么预先操作。如果已经使用过该工具,需要使用—purge-output选项将之前的输出文件删除,如下图所示:
  
图3 将sqlmap output目录中的原输出文件删除
本文会演示一些比较独特的操作。通常人们使用sqlmap时会直接指定url,笔者也是用该工具分析请求,但会先用burp查看请求并将其保存到一个文本文件中,之后再用sqlmap工具调用该文本文件进行扫描。以上就是一些准备工作,下面首先就是先获取一个请求,如下所示:
  get /chintan/index.php?page=user-info.php&username=jonnybravo&password=
  momma&user-info-php-submit-button=view account details http/1.1
  host: localhost
  user-agent: mozilla/5.0 (windows nt 5.1; rv:27.0) gecko/20100101 firefox/27.0
  accept: text/html,application/xhtml xml,application/xml;q=0.9,*/*;q=0.8
  accept-language: en-us,en;q=0.5
  accept-encoding: gzip, deflate
  referer: http://localhost/chintan/index.php?page=user-info.php
  cookie: showhints=0; username=jonnybravo; uid=19; phpsessid=f01sonmub2j9aushull1bvh8b5
  connection: keep-alive
  将该请求保存到一个文本文件中,之后发送到kali linux中,用如下命令将该请求头部传给sqlmap:
  sqlmap –r ~/root/desktop/header.txt
  命令中-r选项表示要读取一个包含请求的文件,~/root/desktop/header.txt表示文件的位置。如果读者用vmware,例如在windows上用虚拟机跑kali,执行命令时可能产生如下图所示的错误提示:
  这里必须在请求头中指定一个ip地址,使kali linux能与xp正常通信,修改如下图所示:
  之后命令就能正常执行了,显示结果如下图所示:
  基本上该工具做的就是分析请求并确定请求中的第一个参数,之后对该参数进行各种测试,以确定服务器上运行的数据库类型。对每个请求,sqlmap都会对请求中的第一个参数进行各种测试。
  get /chintan/index.php?page=user-info.php&username=jonnybravo&password=momma&user-
  info-php-submit-button=view account details http/1.1
  sqlmap可以检测多种数据库,如mysql、oracle sql、postgresql、microsoft sql server等。
  下图是笔者系统中sqlmap正在对指定的请求进行检测时显示的数据库列表:
  首先它会确定给定的参数是否可注入。根据本文演示的情况,我们已经设置owasp mutillidae的安全性为0,因此这里是可注入的,同时sqlmap也检测到后台数据库dbms可能为mysql。
  如上图所示,工具识别后台数据库可能为mysql,因此提示用户是否跳过其它类型数据库的检测。
  “由于本文在演示之前已经知道被检测数据库是mysql,因此这里选择跳过对其它类型数据库的检测。”
  之后询问用户是否引入(include)测试mysql相关的所有payload,这里选择“yes”选项:
  测试过一些payloads之后,工具已经识别出get参数上一个由错误引起的注入问题和一个boolean类型引起的盲注问题。
  之后显示该get参数username是一个基于mysql union(union-based)类型的查询注入点,因此这里跳过其它测试,深入挖掘已经找出的漏洞。
  至此,工具已经识别出应该深入挖掘的可能的注入点:
  接下来,我把参数username传递给sqlmap工具,以对其进行深入挖掘。通过上文描述的所有注入点和payloads,我们将对username参数使用基于boolean的sql盲注技术,通过sqlmap中的–technique选项实现。其中选择如下列表中不同的选项表示选用不同的技术:
  b : 基于boolean的盲注(boolean based blind)
  q : 内联查询(inline queries)
  t : 基于时间的盲注(time based blind)
  u : 基于联合查询(union query based)
  e : 基于错误(error based)
  s : 栈查询(stack queries)
  本例中也给出了参数名“username”,因此最后构造的命令如下:
  sqlmap –r ~root/desktop/header.txt – -technique b – -p username – -current-user
 这里-p选项表示要注入的参数,“–current-user“选项表示强制sqlmap查询并显示登录mysql数据库系统的当前用户。命令得到输出如下图所示:
  同时也可以看到工具也识别出了操作系统名,dbms服务器以及程序使用的编程语言。
  “”当前我们所做的就是向服务器发送请求并接收来自服务器的响应,类似客户端-服务器端模式的交互。我们没有直接与数据库管理系统dbms交互,但sqlmap可以仍识别这些后台信息。
  同时本次与之前演示的sql注入是不同的。在前一次演示sql注入中,我们使用的是前缀与后缀,本文不再使用这种方法。之前我们往输入框中输入内容并等待返回到客户端的响应,这样就可以根据这些信息得到切入点。本文我们往输入框输入永远为真的内容,通过它判断应用程序的响应,当作程序返回给我们的信息。“
  结果分析
  我们已经给出当前的用户名,位于本机,下面看看它在后台做了什么。前文已经说过,后台是一个if判断语句,它会分析该if查询,检查username为jonnybravo且7333=7333,之后sqlmap用不同的字符串代替7333,新的请求如下:
  page=user-info.php?username=’jonnybravo’ and ‘a’='a’ etc..false
  page=user-info.php?username=’jonnybravo’ and ‘l’='l’ etc..true
  page=user-info.php?username=’jonnybravo’ and ‘s’='s’ etc..true
  page=user-info.php?username=’jonnybravo’ and ‘b’='b’ etc..false
  如上所示,第一个和最后一个查询请求结果为假,另两个查询请求结果为真,因为当前的username是root@localhost,包含字母l和s,因此这两次查询在查询字母表时会给出包含这两个字母的用户名。
  “这就是用来与web服务器验证的sql server用户名,这种情况在任何针对客户端的攻击中都不应该出现,但我们让它发生了。”
  去掉了–current-user选项,使用另外两个选项-u和–password代替。-u用来指定要查询的用户名,–password表示让sqlmap去获取指定用户名对应的密码,得到最后的命令如下:
  sqlmap -r ~root/desktop/header.txt --technique b -p username -u root@localhost --passwords
  命令输出如下图所示:
  self-critical evaluation
  有时可能没有成功获取到密码,只得到一个null输出,那是因为系统管理员可能没有为指定的用户设定认证信息。如果用户是在本机测试,默认情况下用户root@localhost是没有密码的,需要使用者自己为该用户设置密码,可以在mysql的user数据表中看到用户的列表,通过双击password区域来为其添加密码。或者可以直接用下图所示的命令直接更新指定用户的密码:
  这里将密码设置为“sysadmin“,这样sqlmap就可以获取到该密码了,如果不设置的话,得到的就是null。
  通过以上方法,我们不直接与数据库服务器通信,通过sql注入得到了管理员的登录认证信息。
  总结
  本文描述的注入方法就是所谓的sql盲注,这种方法更繁琐,很多情况下比较难以检测和利用。相信读者已经了解传统sql注入与sql盲注的不同。在本文所处的背景下,我们只是输入参数,看其是否以传统方式响应,之后凭运气尝试注入,与之前演示的注入完全是不同的方式。


顺其自然evo 2014-10-30 10:38
]]>
优化mysql,还是使用缓存?http://www.blogjava.net/qileilove/archive/2014/10/16/418774.html顺其自然evo顺其自然evothu, 16 oct 2014 01:59:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/16/418774.htmlhttp://www.blogjava.net/qileilove/comments/418774.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/16/418774.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/418774.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/418774.html今天我想对一个greenfield项目上可以采用的各种性能优化策略作个对比。换言之,该项目没有之前决策强加给它的各种约束限制,也还没有被优化过。
  具体来说,我想比较的两种优化策略是优化和缓存。提前指出,这些优化是正交的,唯一让你选择其中一者而不是另一者的原因是他们都耗费了资源,即开发时间。
  优化mysql
  优化mysql时,一般会先查看发送给mysql的查询语句,然后运行explain命令。稍加审查后很常见的做法是增加索引或者对模式做一些调整。
  优点
  1、一个经过优化的查询对于所有使用应用的用户来说都是快速的。因为索引通过对数复杂度的速度来检索数据(又名分制,正如你搜索一个电话簿一样,逐步缩小搜索范围),而且随着数据量的递增也能维持良好的性能。对一个未经索引化的查询的结果做缓存随着数据的增长有时候则可能会表现得更差。随着数据的增长,那些未命中缓存的用户可能会得到很糟糕的体验,这样的应用是不可用的。
  2、优化mysql不需要担心缓存失效或者缓存数据过期的问题。
  3、优化mysql可以简化技术架构,在开发环境下复制和会更加容易。
  缺点
  1、有一些查询不能光通过索引得到性能上的改善,可能还需要改变模式,在某些情况下这对于一些应用可能会很麻烦。
  2、有些模式的更改可能用于反规范化(数据备份)。尽管对于dba来说,这是一项常用的技术,它需要所有权以确保所有的地方都是由应用程序更新,或需要安装触发器来保证这种变化。
  3、一些优化手段可能是mysql所特有的。也就是说,如果底层软件被移植到多个上工作,那么很难确保除了增加索引外一些更复杂的优化技术可以通用。
  使用缓存
  这种优化需要人来分析应用的实际情况,然后将处理代价昂贵的部分从mysql中剥离出来用第三方缓存替代,比如memcached或redis。
  优点
  1、缓存对于一些mysql自身很难优化的查询来说会工作地很好,比如大规模的聚合或者分组的查询。
  2、缓存对于提高系统的吞吐率来说可能是个不错的方案。比如对于多人同时访问应用时响应速度很慢的情况。
  3、缓存可能更容易构建在另一个应用之上。比如:你的应用可能是另一个用mysql存储数据的软件包的前端,而要对这个软件包做任何数据库方面的改动都非常难。
  缺点
  1、如果数据对外提供多种存取范式(例如,在不同的页面上用不同的形式展示),那么让缓存过期或者更新可能会很难,同时/或者可能需要容忍已过期的数据。一个可行的替代方案是设计一套更加精细的缓存机制,当然它也有缺点,即多次获取缓存会增加时延。
  2、缓存一个产生代价昂贵的对象对于那些未命中缓存的用户(见优化mysql的优势#1)而言可能会产生潜在的性能差异。一些好的性能实践表明你应该尽量缩小用户之间的差异性,而不仅仅是平均化(缓存倾向于这么做)。
  3、幼稚的缓存实现无力应对一些微妙的漏洞,比如雪崩效应。就在上周我帮助了一个人,他的数据库服务器被多个试图同时再生同样缓存内容的用户请求冲垮。正确的策略是引入一定级别的锁来将缓存再生的请求序列化。
  总结
  一般情况下,我会建议用户先对mysql进行优化,因为这是我认为开始阶段最合适的凯发天生赢家一触即发官网的解决方案。但长期来看,大部分应用都会有一些用例需要一定程度上同时实现以上这些方案。


顺其自然evo 2014-10-16 09:59
]]>
linux下db2数据库安装教程http://www.blogjava.net/qileilove/archive/2014/10/15/418734.html顺其自然evo顺其自然evowed, 15 oct 2014 01:57:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/15/418734.htmlhttp://www.blogjava.net/qileilove/comments/418734.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/15/418734.html#feedback1http://www.blogjava.net/qileilove/comments/commentrss/418734.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/418734.html最近因为需要在学习db2数据库,本教程讲解db2数据库在inux下的安装步骤。
  安装前请查看 db2版本和许可证 说明来增加了解,先弄明白改安装什么版本,这里我用的是最新的express-c版本,这个版本是提供给个人用的版本。
  管理客户端从v9.7版本之后就不再带有控制中心了,而是使用 data studio client。
  版本:
  linux版本下的db2数据库采用的官方免费版本,用的centos6.2。
  安装过程:
  1、下载:db2_v101_linuxia32_expc.tar.gz
  2、解压,解压完成后会在当前目录下有一个 ./expc 文件夹
  [root@localhost opt]# tar -zxvf db2_v101_linuxia32_expc.tar.gz
  发布地址: http://www.cnblogs.com/zxlovenet/p/3972766.html
  3、进入这个目录
  [root@localhost opt]# cd expc/
  4、执行安装
  [root@localhost expc]# ./db2_install
  5、添加组和用户:
  组(用户名)
db2iadm1(db2inst1)
db2fadm1( db2fenc1)
[root@localhost expc]# groupadd -g 2000 db2iadm1
[root@localhost expc]# groupadd -g 2001 db2fadm1
[root@localhost expc]# useradd -m -g db2iadm1 -d /home/db2inst1 db2inst1
[root@localhost expc]# useradd -m -g db2fadm1 -d /home/db2fenc1 db2fenc1
[root@localhost expc]# passwd db2inst1
[root@localhost expc]# passwd db2fenc1
  6、安装 license(产品许可证) ps:如果是expressc版本就不用做
  [root@localhost adm]# pwd
  /opt/ibm/db2/v10.1/adm
  [root@localhost adm]# chmod -r 775 *
  [db2inst1@localhost adm]$ ./db2licm -a /tmp/seagull/db2v10/license/db2ese_c.lic
  7、创建实例和样本
[root@localhost instance]# pwd
/opt/ibm/db2/v10.1/instance
[root@localhost instance]# chmod -r 775 *
[root@localhost instance]# ./db2icrt -p 50000 -u db2fenc1 db2inst1
[root@localhost instance]# su - db2inst1
[db2inst1@localhost ~]$ db2sampl
creating database "sample"...
connecting to database "sample"...
creating tables and data in schema "db2inst1"...
creating tables with xml columns and xml data in schema "db2inst1"...
'db2sampl' processing complete.
[db2inst1@localhost ~]$ db2start
sql1026n the database manager is already active.
[db2inst1@localhost ~]$ db2 connect to sample
database connection information
database  = db2/linux 10.1.2
 authorization id = db2inst1
local database alias = sample
[db2inst1@localhost ~]$ db2 "select * from staff"
 8、创建 das 管理服务器
  为了远程客户端能够用控制中心来控制数据库服务器,需要在数据库服务器上安装 das,当然,如果只是远程连接而不是远程管理,可以不用装,这里我安装了一下。
[root@localhost expc]# groupadd -g 2002 db2asgrp
[root@localhost expc]# useradd -m -g db2asgrp -d /home/db2as db2as
[root@localhost expc]# passwd db2as
[db2as@localhost ~]$ su - db2as # 这里测试新建用户
[db2as@localhost ~]$ su # 这里进入root权限
[root@localhost ~]# cd /opt/ibm/db2/v10.1/instance/
[root@localhost instance]# ./dascrt -u db2as
dbi1070i program dascrt completed successfully.
[root@localhost instance]# su - db2as
[db2as@localhost ~]$ db2admin start
sql4409w the db2 administration server is already active.
  9、设置端口号
  vim /etc/services
  在最后增加一行 # ps:vim快捷键,在命令模式下输入“g”跳刀最后一行。
  db2inst1 50000/tcp
  10、db2 配置,要切换到用户 db2inst1
  su - db2inst1
  db2set db2_extended_optimization=on
  db2set db2_disable_flush_log=on
  db2set autostart=yes
  db2set db2_striped_containers=on
  db2set db2_hash_join=y
  db2set db2comm=tcpip
  db2set db2_parallel_io=*
  db2set db2codepage=819 # ps:这个地方比较重要
  # db2 update database manager configuration using svcename db2inst1
  11.将svcename设置成/etc/services中的端口号或者服务名了吗?
  [db2inst1@localhost ~]$ db2 get dbm cfg|grep svcename
  tcp/ip service name (svcename) =
  ssl service name (ssl_svcename) =
  发布地址: http://www.cnblogs.com/zxlovenet/p/3972766.html
  找到svcename,如果当前值不是服务器端的端口号或者服务名,进行更新设置。
  [db2inst1@localhost ~]$ db2 update dbm cfg using svcename db2inst1
  # db2 update dbm cfg using indexrec access
  [db2inst1@localhost ~]$ db2 get dbm cfg|grep svcename
  tcp/ip service name (svcename) = 50000
  ssl service name (ssl_svcename) =
  # ps:svcename 在客户端连接时需要用到
  12.在启动db2之前需要先关闭防火墙,不然的话根本就不能连接(这个地方的疏忽纠结了好久),在root用户下执行:service iptables stop
  13.开启db2,执行:db2start ,如果已经开启状态,那就先停止,执行:db2stop 。
  ps:参考链接如下
  http://www.db2china.net/home/space.php?uid=92501&do=blog&id=25771
  http://blog.csdn.net/xiaolang85/article/details/3887459
  设置查看:
  ps:重启机器后遇到了一个问题,就是关闭防火墙无反应,开启关闭数据库无反应,远程不能连接到数据库,解决办法是重启了服务器,然后按照顺序关闭了防火墙,然后重启了db2数据库。


顺其自然evo 2014-10-15 09:57
]]>
网站地图