续上一篇随笔:https://www.cnblogs.com/kingstarer/p/12249028.html《工做碰上的技术问题及处理经验》(四)html
我这人记忆力比较差,常常出现有些知识学了不久后就忘了,或者有些问题花了不少时间百度解决后,再过一段时间碰上时只有模糊印象,却忘了具体解决方法。前端
最近几年工做时我开始有意识地把登记天天工做碰上的技术问题作个简单笔记。java
通常上班时间比较忙,只能草草记了一两句话。等过一段时间,我会把这个笔记整理一下,把问题和处理经验整理通顺,以加深本身的印象。node
20190402: 今天碰上一个脚本文件编码与系统编码不符,致使sed运行报错的问题。我脚本里面写了一个命令sed -e 's/月份/月份 ${V_MONTH}/g' 执行时报错"sed: -e expression #1, char 21: unterminated `s' command" 我在执行sed以前先执行set -x,打开脚本调试模式。看到输出是sed -e "s/\324\302\267\335/\324\302\267\335 201904/g"。 这个输出说明编码是GBK,由于一个中文占了两个字节。但我系统的LANG设置为en_US.UTF-8。不相符,因此须要改一下。 20190407: 今天发现xargs命令作字符串处理仍是挺方便的,之前知道用它来跟管道组合处理参数太多超过命令行限制的状况。这里摘录几个用法: 替换字符串:echo "nameXnameXnameXname" | xargs -dX 多行输入单行输出:(echo a; echo b; echo c) | xargs 组装shell命令:cat arg.txt | xargs -I {} ./sk.sh -p {} 20190408: 今天发现sourceinsight双击选中文字后会自动被修改,变成一个奇怪的问号图标。开始觉得是我键盘有键被卡住了,挨个键检查了一下,没发现问题。 后来偶然发现原来我打开了金山词霸,想起之前也看过网友吐槽,词霸里面的取词和划译功能实现方法很粗暴,会不停往系统发快捷键消息。 因而尝试把金山词霸关了,果真好了。 20190409: 今天发现oracle的systimestamp类型是带时区的timestamp,须要用cast(systimestamp as timestamp)转换一下才变成不带时区的。 今天用proc*c写的程序导出数据库表数据,发现有一些字段值是NULL,但我程序没报错。理论上proc若是不用指示变量,取出空的数据时会报错的。 后来查查,发现原来我这个程序用proc*c预编译时设置了UNSAFE_NULL=yes,因此没报错。 20190410: 今天发现oracle有一个语法insert all,能够指定一条记录同时插到两个库表: insert all into t1(c1) int t2(c2) select * from t; proc*c执行dml语句时支持预编译一次,执行sql屡次。不过前提是要设置选项release_cursor=no(默认是no) 今天发现proc有一个参数:prefetch,指定sql语句句柄打开后预先从数据库取出多少条记录。这个参数默认是1,批量任务能够考虑把它改大,有助于提升性能。 今天想用gcc的-Og选项编译程序,发现竟然不支持。估计是我用的版本过低了。网上说-Og选项只会打开与-g不冲突的优化选项。 20190415: 今天发现cp有一个参数-p,复制时保留原文件的修改时间:cp -p old new shell清空文件的技巧 true命令: true > emptyfile 20190416: 用awk写了一个辅助宏代码对齐的脚本 # 输入宏代码,脚本会在每行后面补齐空格和\ awk -v v_tab_lenth=8 '{ # 首先读取全部输入行 计算全部输入文本单行最大长度 v_arr_input[NR] = $0; v_str_len = length($0); v_arr_input_len[NR] = v_str_len; if (v_str_len > v_max_len) v_max_len = v_str_len; } END{ v_max_tab_cnt = int(v_max_len / v_tab_lenth) + 2; print "v_max_tab_cnt = "v_max_tab_cnt for (i = 1; i <= NR; ++i) { v_str_tab_cnt = int(v_arr_input_len[i] / v_tab_lenth); v_tab_cnt = v_max_tab_cnt - v_str_tab_cnt - 1; #if (v_str_tab_cnt * v_tab_lenth < v_arr_input_len[i]) v_tab_cnt = v_max_tab_cnt - v_str_tab_cnt - 1; #else v_tab_cnt = v_max_tab_cnt - v_str_tab_cnt; # print "v_tab_cnt = "v_tab_cnt, "v_str_tab_cnt = "v_str_tab_cnt, "v_arr_input_len[i] = " v_arr_input_len[i] printf("%s", v_arr_input[i]); for (j = 0; j < v_tab_cnt; ++j) printf("\t"); print("\\"); } }' tmp.txt 20190417: 今天发现一个函数fcloseall(_fcloseall),做用是把fopen打开的文件句柄全关了。 但我实际测试,发现fopen打开一个句柄fp,而后调用fcloseall,但这个fp句柄还能够正常读写和关闭。 不过确实证实它有fflush的做用。 20190420: 今天发现proc查询数据到char *类型缩主变量,竟然是经过strlen计算其空间大小。 这个设定好奇怪。在官方文档里面也提醒了调用者,须要用非'\0'字符填充空间。 proc执行rollback/commit会影响sqlca.sqlcode,因此若是须要这个值要先备份起来。 20190423: 今天建立一个分区表时发现oracle在建立表的速度比删表的速度快不少。 建立语句虽然很长,但oracle通常在十几毫秒内能完成,删表语句很短,但执行要数秒钟。 暂时不知道是什么缘由致使的。 20190424: 今天复习了oracle的savepoint语法: savepoint a; rollback to a; 今天我写了一个函数,使用proc*c的数组批量操做技巧,一次插入N条记录。 可是有一个问题没解决,若是在插入过程当中数组里面某些元素因为数据异常插入失败怎么处理? 我暂时的解决方法是:插入前先使用savepoint创建一个保存点,若是插入失败则回滚到该保存点。 不知道plsql里面的forall命令是怎么实现的使用forall批量插入数据时,若是某个数据插入出错会忽略,继续执行。 全部出错记录会存在sql%bulk_exceptions数组的。 20190428: 今天同事分享的一个问题:进行非功能测试,随着时间增加,交易速度有明显降低。 后来查了一下日志,发现有一些sql执行耗时异常。经过分析sql执行计划,发现sql没走索引。 再进一步分析缘由,是由于库表没有及时作统计收集,oracle觉得是空表,原本应该走索引的,给走了全表扫描。 通常认为,库表记录较小(小于100)或者查询的数据量超过总数据的10%走全表扫描比走索引扫描快。(一次顺序IO比屡次随机IO快) 2190506: 今天花了点时间查了一个proc的问题: 执行update语句时没找到记录,sqlca.sqlcode返回1403,可是前面我用EXEC SQL WHENEVER SQLERROR DO指定的proc错误处理函数没有被调用。 后来把.pc文件翻译成.c文件看,才知道EXEC SQL WHENEVER SQLERROR DO指定的函数只有在sqlca.sqlcode < 0时才会被调用。 今天还注意到一个oracle语法细节:select for update后面还能够跟上of 字段,指定只锁定记录哪些字段。 select from hch for update of c1; 20190507: 查看正在运行程序环境变量的方法: strings /proc/${PID}/environ 20190508: 今天使用valgrind检查程序内存使用状况,发现有几个出错位置函数堆栈里面没有main,并且里面都是一些oracle底层的函数。后来发现缘由是出错位置函数调用层次太深,超过了默认值12。 我从新启动valgrind,加上参数--num-callers=100,这样就能显示从main到出错位置的全部函数。 20190509: 今天看到了这样的代码: if (bFlag) { EXEC SQL CONTEXT USE :ctx; } else { EXEC SQL CONTEXT USE DEFAULT; } EXEC SQL ...; 写代码人的本意根据bFlag的值决定使用不一样数据库链接执行sql,但这样写是有问题的,由于EXEC SQL CONTEXT并非一个语句。 它有点相似C语言的宏定义,在预编译后根本不存在。(把.pc文件预编译成.c后"EXEC SQL CONTEXT USE"这段代码就是一段注释) 他这样写代码问题就跟用C语言这样写代码同样: #define SQL_CONTEXT_USE ctxDeault if (bFlag) { #undef SQL_CONTEXT_USE #define SQL_CONTEXT_USE ctx } else { #undef SQL_CONTEXT_USE #define SQL_CONTEXT_USE DEFAULT } EXEC_SQL(SQL_CONTEXT_USE); //不管bFlag的值是什么,这里都是用EXEC_SQL传的值都是ctxDeault 正确写法应该是这样: if (bFlag) { EXEC SQL CONTEXT USE :ctx; EXEC SQL ...; } else { EXEC SQL CONTEXT USE DEFAULT; EXEC SQL ...; } 201900512: 今天一下网友分享一个案例:他用浏览器访问某个网站时能正常获取页面信息,但用爬虫访问时却获取不到。 他已经修改了http请求头,把agent改为跟浏览器的同样也不行。 后来他发现原来是访问网站时服务器会返回一段js,浏览器执行那段js后才能正常生成页面信息。他的爬虫不支持js解析,因此出了错。 201900513: oracle应用程序,有时会须要使用sysdate(或者序列号)修改库表字段,但又想知道修改后的值是什么。这时可使用returning into 子句,示例代码以下: set lines 1000 pages 1000 set serveroutput on alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'; alter session set nls_timestamp_format='yyyy-mm-dd hh24:mi:ss.FF6'; alter session set nls_timestamp_tz_format='yyyy-mm-dd hh24:mi:ss.FF6 TZR'; drop table tab_hch; create table tab_hch(c1 date, c2 timestamp); declare v_dt date; v_dtmicro timestamp; BEGIN insert into tab_hch(c1, c2) values(sysdate, systimestamp) returning c1, c2 into v_dt, v_dtmicro; dbms_output.put_line('c1 = ' || v_dt); dbms_output.put_line('c2 = ' || v_dtmicro); -- 这里输出的时间就是新插入的记录c2的值 END; / col c1 for a20 col c2 for a32 col c3 for a20 col c4 for a34 -- 比较c2与dbms_output.put_line的值,看是否一致 select c1, c2, sysdate c3, systimestamp c4 from tab_hch; 20190515: oracle 交换分区若是存在全局索引,会致使全局索引失效,能够在交换分区时加上with update global index 20190529: sqlplus绑定变量用法: var v_hch number; exec :v_hch := 1; print :v_hch; select :v_hch from dual; 20190530: 今天碰上makefile里面执行cd失效致使递归编译的问题。事情是这样的:有一个程序编译时要求先到子目录下面执行makefile编译后,再回到当前目录编译。因而我写了下面这个makefile。 prog: cd common make $@ cd .. make $@ 结果编译时发现make被无限循环调用了,网上查了一下,要这样写cd common && make $@。原来每次执行一行命令后,makefile会从新回到当前工做目录。因此我原来的makefile等于无限循环调用make编译。 今天有网友问我他们系统有一个一个进程卡住,不知道是死循环了仍是在等待什么条件,要怎么办。我建议他用pstack看一下堆栈,结合代码分析程序的状态。 20190531: 写了一个awk脚本,用于把长行拆成多个短行,里面考虑到了行尾单词连续性问题: awk -v v_line_len=70 '{ v_str = $0; v_TotalLen = length(v_str); while(1) { v_str_sub = substr(v_str, 1, v_line_len); nLen = length(v_str_sub); if (nLen < v_line_len) { print v_str_sub; break; } nLen = v_line_len; v_ch = substr(v_str_sub, nLen, 1); # 若是结尾不是非字母或者数字,则一直往前找,直到找到第一个非字母或者数字的字符 # 若是找了20个还找不到,则放弃 这样作是为了不行尾的单词被一分为二 while ((v_ch == ":") || (v_ch >= "a" && v_ch <= "z") || (v_ch >= "A" && v_ch <= "Z") || (v_ch >= "0" && v_ch <= "9")) { --nLen; v_ch = substr(v_str_sub, nLen, 1); if (nLen <= v_line_len - 20) { nLen = v_line_len; break; } } v_str_sub = substr(v_str, 1, nLen); print v_str_sub; v_str = substr(v_str, nLen + 1); } }' 20190603: 今天学习了makefile一个特殊变量:MAKECMDGOALS 这个变量记录了命令行参数指定的终极目标列表。 举例:执行make debug命令,MAKECMDGOALS的值是debug。在递归脚本里面这个参数颇有用。 make还有其它几个特殊变量,分别表明当前目录,makefile名称,make版本等 20190604: 今天碰到一个状况:df显示磁盘空间还剩不少,但用cp命令拷贝生成新文件时提示no space left on device。 上网查了一下,说多是磁盘inodes空间满了,用df -i能够查看。 我试了一下,果真如此。用df能够看出inodes空间占用 100%。cd到怀疑有大量文件的目录下,ls时卡住了,没法定位是什么文件致使的。 没办法最后只能把目录删了重建。 20190605: oracle写sql时若是须要指定转义字符(k逃逸字符),可使用escape关键字。例如: select owner, table_name from all_tables where table_name like '%\_17_\_%' escape '\'; -- 找出全部以包含"_17?_"的表名,?表明一个任意字符 fuser能够查看文件被哪些进程打开 ${0}:${LINENO} shell输出日志加上这个前缀,能够更方便定位 bash里面还可使用${FUNCNAME[0]}输出当前函数名称 一个日志输出函数示例: logerr() { echo "error at ${BASH_LINENO[1]}${FUNCNAME[1]} $*" } 20190613: 因为oracle的索引是不记录NUUL值记录,因此惟一索引列是能够存在多个为NULL的记录的 另外,oracle的NULL和空串''是等价的 20190614: 写了一个方便查看文件数据的awk脚本(读取行,拆成多列显示) awk -F '\\|@\\|' '{ printf("%s:%d\n", FILENAME, FNR); for (i = 1; i <= NF; ++i) { printf("% 4d:%s\n", i, $i); } getline < "-"; }' 20190616: 一个web请求可能须要通过的cdn,dns负载均衡,f5负载均衡,nginx反向代理,消息队列,redis,数据库(读写分离,集群),文件缓冲等这么多种缓存机制 20190620: 使用static变量时,记得注意变量之间关连关系。我此次就踩了坑: 我在程序里面使用了两个static变量s_this_date缓存当前时间,s_next_date缓存s_this_date的下一天。 为减小计算时间消耗,只有当s_this_date变化时,才会计算s_next_date。 但代码里面有个问题,存在修改了s_this_date后,在s_next_date修改前函数就退出的状况。 这样就致使s_next_date有时跟s_this_date不是差一天的关系。 20190630: select for update是上锁,不是检查有没有锁 20190701: 今天使用了merge语句帮同事优化了一个语句: update tab_check_task t set Mcht_Name=(select Mcht_Name from tab_mcho_sre where mcht_no=t.mrch_id ); 13分钟没跑完 merge into tab_check_task t using tab_mcho_sre mcht on (mcht.mcht_no=t.mrch_id) when matched then update set t.Mcht_Name = mcht.Mcht_Name; 4分钟跑完 今天一个同事说他在.bash_profile配置了两个环境变量,但从新登陆后只有其中一个生效了,问我怎么回事。 我建议他执行sh -x .bash_profile,看是哪里出错了。他执行后很快回复我,是.bash_profile后面加载了另外一个脚本,那个脚本里面有同名变量,相互覆盖了。 sh -x 是调试shell的利器。‘ 20190704: 今天发现time命令和\time调用的是不一样的程序,\time调用的是/usr/bin下面的time程序,而time则是调用shell内置的功能 今天看到一个调试一个release程序的方法: 先使用-g从新编译一次程序,而后取出变量信息 objcopy --only-keep-debug projedtd projedtsymbol.dbg 再使用这些变量信息去调试release程序 gdb -q symbol=projedtsymbol.dbg --exec=projectr x /10x $sp # gdb查看当前程序栈的内容: 打印stack的前10个元素 20190705: 调试内存问题时,能够设置环境变量 export MALLOC_CHECK_=3 这样程序在发现内存异常时会打印出错信息并退出 20190712: 今天来上班,发现昨天晚上挂的一个crontab任务没启动。一开始没想明白是什么缘由,觉得是任务脚本有问题,查半天没查出来。 后来在同事建议下,我试了加了一个简单的crontab任务,设置成1分钟后跑,发现也没启动。这才肯定原来是crontab服务没启动,可使用如下命令确认: service crond status 20190715: proc调用存储过程,出参,也要初始化,否则使用valgrind检查时会提示未初始化的内存。 20190716: 今天使用vallgrind检测程序时,出现不少内存泄漏提示。 但其实我确认代码没写错,后来查了一下,是由于使用了glib的一些数据结构,里面使用了内存池。 而且查到了,若是设置环境变量G_SLICE=always-malloc这样就不会启动glib内存池。 20190717: 今天看代码时发现一段逻辑,须要判断一张数据库表有没有记录,里面直接用了select count(*) from tab检查,其实可使用 select count(*) from tab where rownum < 2,由于要检查有没有记录,只要有一条记录就能够判断,不须要全表扫一次。 20190718: 从csdn上保存的博文,在没有连公网时打开,老是过一会就自动重定向到csdn.net,很烦人。虽然知道确定是某段js搞鬼,但一直没搞清楚是哪段。 今天发现用谷歌浏览器按f12能够单步调试网页,利用这功能终于定位到了“元凶”。 <img src="https://blog.csdn.net/chuxuan909/article/details/72465748?utm_source=blogxgwz0" onerror="setTimeout(function() {if(!/(csdn.net|iteye.com|baiducontent.com|googleusercontent.com|360webcache.com|sogoucdn.com|bingj.com|baidu.com)$/. test(window.location.hostname)) {window.location.href="\x68\x74\x74\x70\x73\x3a\x2f\x2f\x77\x77\x77\x2e\x63\x73\x64\x6e\x2e\x6e\x65\x74"}},3000); "> 把onerror批量替换成onerror1便可。这段代码里"\x68\x74\x74\x70\x73\x3a\x2f\x2f\x77\x77\x77\x2e\x63\x73\x64\x6e\x2e\x6e\x65\x74" 其实就是https://www.csdn.net 20190719: kafka阅读心得: 观察脏页 cat /proc/vmstat | egrep 'dirty|writeback' 启动g1垃圾回收器 export KAFKA_JVM_PERFORMANCE_OPTS='-server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+DisableExplicitGC -Djava.awt.headless=true" kafka-server-start.sh -daemon server.propertities 20190724: proc对匿名结构体支持不大好,建议尽可能使用typedef struct __StuName_t{}StuName_t;代替typedef struct {}StuName_t; 20190725: sqlldr加快装载速度的参数设置建议: sqlldr errors=9999999 control=tab.ctl log=tmp.txt sreamsize=256000 bindsize=2560000 userid=stlm_o/stlm_o@RCC8TPD2 direct=TRUE rows=1000 20190726: 今天发现有一些商家使用退货交易套利: 第一天先作了一大笔消费,次日一开门就作了退货交易。因为这时商户资金不足,为了避免影响用户体验,咱们系统会先垫钱给用户,后面再从商户的帐户扣钱。 但有一些不法商户跟消费者合做,退款后当即注销商户,致使系统出现短款。 为了解决这个问题,咱们紧急作了一个白名单功能,不在白名单的商户,当日营业额不足时不容许退货。(这种状况商家必定要退货时,须要本身先作一笔大额消费) 20190731: 今天过来发现crontab任务没启动(检查crontab任务重定向输出的日志,发现不存在)。检查一下,发现由于是硬盘没空间了。这才知道原来硬盘满了会致使crontab调度异常。 20190801: 今天才发现df出来的size != used + free,查了一下,说缘由有两个1 inode节点空间占用了一些磁盘空间,2 系统会占用一些预留空间,以便出现磁盘空间满时止root用户登陆处理(通常是0.05 * size)。不过个人系统加上这两项空间,仍是差一些,不知道是否是还有其它隐藏的占用空间状况。 20190810: 这段时间都在研究kafka,kafka其实就是一个分布式消息队列中间件,主要用于吞吐量高(号称每秒十万写,百万读),但业务逻辑简单(如数据同步,通知)的场景。 kafka借助zookeeper实现了集群,高可用特性,自己又支持多副本功能,集群少许机器出现故障时仍可正常使用。但kafka的消息一致性比较差,容易出现消息丢失或者重复消息的状况。 kafka支持多个不一样客户端订阅同一个消息主题,这样能够作到一份消息多个场景使用,这点对于数据分析特别有利。另外,kafak的消息都是落盘存储的,因此生产者跟消费者耦合很是低,能够分别独立部署运行。 20190812: 这几天用glib写了一个多线程的程序,连接时报g_thread_init函数未定义(undefined reference to `g_thread_init'),但奇怪的是我明明有libglib-2.0.a,原来网上查了一下,原来是要额外连接libgthread-2.0.a cout从右到左计算,从左到右输出 lsof -u username # 列出用户全部打开的文件 20190814: 今天编译libcjson.a,发现默认的编译选项是没有开启-O2的,不知道为何。我把它改了一下,增长-O2选项,发现只快了一点。 跑10万次cJSON_test,耗时从1.15s降到0.97。又测试了5000000次的,发现分别耗时是55秒和45秒。仍是有点效果的,但效果不明显,先使用默认的吧。 今天又出现某个bug增长打印日志 就不出现,不加就出现的状况。后来仔细看代码,是由于我有两个不一样文件,同时声明了一个全局变量(名字同样),其中一个有初始化,一个未初始化,致使两个变量连接时被合并成一个,从而互相影响。 20190815: 今天发生一个事情,因为沟通问题,我跟同事改了同一个word文件,只能想办法跟他的合并。网上找了一下,说word的审阅选项卡下面有比较功能。 试了一下,确实是能够,但不是很直观。后来经同事提醒,原来svn自带启动word比较功能。 20190820: 今天发现ue有一个好用的快捷键F5,做用是把大写数据库列名转成驼峰式的大小写混合的单词。例如THIS_IS_A_TEST会被变成This_Is_A_Test 20190821: 小知识点:free命令输出的内存使用信息里面used并不表明真正可用内存,可用内存是free + buffer + cached之和 20190822: extern int g_lib_flag = 0; //连接时报错 extern不能增长初始化 20190823: 今天生产系统发现有一些交易存在冲正交易比正交易先到,致使对帐不平的状况。 出现bug的主要缘由是咱们接到冲正请求时发现数据库没有正交易,直接就返回前端冲正失败(交易不存在),但没有登记流水。后面正交易过来时咱们当普通交易正常处理了。但前端系统不知道,因此没有重复发起冲正请求。 暂时要求前端严格控制顺序发送交易,之后再出现须要考虑一些机制避免这种差别。 20190904: 这两天使用Loadrunner对程序进行压测,压测过程当中常常提示压力机cpu使用率超过80%的提示。开始时我没怎么在乎,想着不是目标机80%,压力机没到100%应该没事。 后来偶然把测试脚本改一下,压力机cpu消耗下来,发现目标机tps竟然有明显升高。 看来之后要注意一下。 oracle默认删除表后不会清除空间,而是放到回收站。若是要强制收回这些空间,可使用select * from user_recyclebin;查出表名,而后使用 purge table "表名"; 20190914: 今天发现一个bug: 咱们一个程序在执行数据库查询过程当中,收到信号,转去执行中断处理函数。 结果函数里面也有数据库查询操做,致使死锁了。(proc的api对于这种状况没处理好) 临时解决方法是在数据库操做期间先屏蔽了信号,不过这样可能致使信号漏处理,之后须要优化。 20191030: 以前对日志组件作了优化,使用本身写的带缓存的localTimeCache代替localTime,减小锁竞争。 今天写了一个测试,发如今高频调用下时,有时会出现跟localTime的秒数有差别的状况,代码以下: while (1) { int *pSecCache = &localTimeCache(&time)->tm_sec; int *pSec = &localTime(&time)->tm_sec; LogInfo("cache %d", *pSecCache); LogInfo(" nocache %d\n", *pSec); } 后来仔细分析,原来LogInfo里面也会调用localTimeCache,致使pSecCache的值发生了变化。对于这种静态变量使用,须要多注意。 今天又碰上一个进程由于信号处理函数出bug的状况:在调用system函数时接到信号,转到信号处理函数时又调用了system,致使死锁。 20191030: proc查询数据库数据到char数组时,若是目标数组空间不足,则会截断(但仍是会以\0会结尾)。 若是数组空间比数据库字段长度长,则剩下的空间会以空格填充。 20191114: void func(char * const arr[]) 只读字符串数组 strcpy(arr[0], "123"); //ok arr[0] = "123"; // not ok 20191125: oracle 在线压缩分区的方法: 1 完美方法 使用12 c的move online功能 2 变通方法a 先将要压缩的分区数据导出来到临时表并压缩 把临时表的数据跟待压缩分区作在线交换(要加上with update indexes) 从临时表里面找操做期间变动的记录,更新回压缩分区 3 变通方法b(压缩分区不须要查询的状况) 建一个空表 把分区的数据跟空表交换 对表作压缩 20191126: oracle作分区交换时,可使用including indexes,在作交换分区时顺便维护local索引 float类型的变量在计算时很容易损失精度:0.1循环加8次 > 0.8 double也会,但比float损失精度的几率会低一些。 20191127: 今天出现一个问题:我在程序里面一个sql使用了hint:result_cache想提升查询速度,单进程测试时发现确实有明显改善。 但到生产机器时,多进程环境跑的时候却致使了大量lanth free事件,反而拖慢了速度。后来dba临时关闭了result_cache功能才恢复。 20191204: 进程数估计 机器cpu跑满 看是否有堵塞 交易太频繁,没有发心跳 mq recv 20191205: oracle使用merge into有时也会由于主键冲突失败,主要是出如今高并发插入的场景。 20191206: watch命令特别方便监测进程运行状况:执行 watch 'ps aux www|grep -w -E "ProgName|TTY"' 系统会显示进程资源占用状况,而且自动每2秒刷新 20191207: 今天使用valgrind检测程序时,发现好多invalid write。仔细检查,发现是由于 strptime函数没有填充目标变量的夏令时字段,致使这个字段是未知字节。而后我又拷贝了这个变量的值,就出现这个问题。 解决方法是strptime函数执行后再设置tm_isdst为0 20191208: 今天发现c++的throw比较消耗资源,即便没触发throw部分代码。 我写了两个程序,代码是同样的,只是一个加了try catch,另外一个没有加。 编译后运行,发现效率相差20% 20191210: 今天使用callgrind检测程序性能时,发现我有一个函数虽然有调用,可是在callgrind输出结果却看不到实际调用状况。 后来通过屡次测试,发现原来是这个程序被编译器自动内联了。虽然我没有指定inline,也没有加-O,但编译器仍是将它内联了。 两个静态库的函数互相调用,会致使连接时不管怎么调整顺序,都有可能报“找不到对象”,这时能够多连接几回: 例如我有libA.a libB.a相互调用了,写makefile时可这样:-lA -lB -lA -lB。不过这只是临时处理方案,实际上不该该出现这样的相互调用的状况。 linux消息队列好像没有支持io多路复用的api,我设想了一个解决方案: 启动一个专门的读线程,使用阻塞读消息队列,若是读到了消息,则发送一个信号给主进程监听的句柄(例如匿名管道) 20191211: 最后生产数据库空间告警,只能把一些不经常使用的流水表作压缩,以节省空间。幸亏oracle提供了压缩表的功能。 20191212: 最近半年作了一个查询库同步的功能,过程仍是很折腾的: 最开始打算直接使用goldengate同上交易库的表和查询库的表,这是最方便的。 可是运维团队说没有购买这个工具,并且有安全问题。因而只能做罢。 后来又想着在业务库表加上触发器,把修改内容登记到一个日志表,再写一个程序根据日志表同步数据到查询库。 但运维团队又说不能加触发器,由于触发器影响性能。 以后有同事提出使用物化视图,但我查了一下网上,oracle的物化视图功能bug不少,没建议。 最后偶然间,我查proc开发文件时发现oracle提供了一种returning into的语法,能够返回update/insert修改后记录的内容。 因而最后决定: 1 而且给业务表增长修改时间字段,insert或update时顺便更新这个字段。 2 在全部修改数据库流水表的代码增长returning into子句,把修改结果查询回来。 3 把返回的记录发给同步进程,同步进程把记录merge到查询库的表 4 为防止顺序错乱,同步查询库时须要加上判断,若是修改时间比数据库记录的时间早,则不处理 20191216: 文件编码不是文件的属性之一,这是不少人没搞清楚的。他们每每会说“我文件已经保存成gbk编码,为何传到linux上打开仍是乱码” 其实问题就是文件编码不是文件的属性,linux上的文件工具打开文件时只能“猜想”文件的编码,若是它猜错了,显示就是乱码。 20191217: 逻辑尺:一个字段,其中的各个位,由咱们本身规定为0、1。 而后,用这一串0、1,依次去选择两种操做。 这个字节,每每有人称之为逻辑尺。 20191218: 今天用proc编译.pc文件时出现core,看缘由是段错误。 后来检查一下,是因为文件路径太长,超过100个字符,触发proc的bug 20191219: vim显示不了回车符解决方法:vi -b vim输入回车符方法:按住ctrl,再按v,再松开v按m 20191220: 今天使用loadrunner压测的过程当中,报了很多"server has shut down the connection"的错误 观察被压测机器的接入程序,却没有发现异常。 猜想是因为客户端机TIME_WAIT太多形成的,不过修改后也没多大改善。具体缘由暂时还不知道 20191223: Disql是DM数据库自带的数据库命令行客户端工具。相似于sqlplus,不过作得不太好。 今天随便试用了一下,就发现一个bug:进入disql后,若是不执行sql,直接按ctrl + c,会致使程序退出 20191225: %08s,不是用0左补齐,而是用空格 20191226: oracle在多个会话查询同一条记录,容易出现LanchFree竞争事件 20191227: 今天作非功能测试,发现有一个交易跑一会tps就急剧降低。一开始我觉得受清理日志影响,但后来把日志清理停了也同样。 观察vmstat输出,tps降低时cpu使用wait的数据急剧上升,而且so也上升。猜想是因为内存换页影响。使用ps aux www观察,发现进程占用的内存大涨。 iostat -x 2 5 # 每隔2秒打印io信息 共5次 20191228: gdb打开core文件,使用where发现堆栈异常,有一些函数根本不可能调用到,但却显示在输出里面。 后来发现core文件生成时间比程序的修改时间还早,说明程序被修改过。后来我找了修改前的程序,从新用gdb调试,这里where输出就正常了。 20191230: 今天启动业务系统时出现有一些进程打开监听端口时失败,重启时就行了。 仔细分析日志,发现问题是某些进程使用的随机端口正好与监听端口冲突了。 20191231: 今天压测时,发现tps忽然降低。看vmstat,bi忽然增长,wa增长。查看free,发现buffer忽然减小,原来是有进程占用了太多内存致使的。 20200106: 今天作非功能测试时,发现数据库不少"cursor: pin S wait on X"的等待事件。 百度查了一下,出现这个等待事件的缘由不少,其中一个比较常见的状况是数据库硬解析sql太多。 但咱们系统高并发的sql都是使用绑定变量的,理论上不该该出现不少硬解析。因此当时认为不是这个问题。(其实当时应该检查一下硬解析次数再下结论) 后来偶然间发现有一些20年的流水表没建,致使sql执行时出现"table or veiw not exist"的错误,这才明白过来为何会有不少硬解析。 后来把表建好后再跑就没这个等待事件了。 20200107: 看网上的实验说是rac切换时,该节点没提交事务会自动回滚 若是应用此时不进行rollback操做,再执行其余语句(包括commit)都会报ora-25402 20200108: loadrunner参数取随机值设置方法: Select next row: Random Update Value On: Each iteration 20200109: 查看系统在监听的端口和对应程序名:netstat -anp|grep LIS 20200110: 数据库缓慢,执行 set linesize 240 col sid format 9999 col s# format 99999 col username format a15 col event format a30 col machine format a20 col p123 format a18 col wt format 999 col SQL_ID for a18 alter session set cursor_sharing=force; SELECT S.SID, S.SERIAL# S#, P.SPID, NVL(S.USERNAME, SUBSTR(P.PROGRAM, LENGTH(P.PROGRAM) - 6)) USERNAME, S.MACHINE, S.EVENT, S.P1 || '/' || S.P2 || '/' || S.P3 P123, S.WAIT_TIME WT, NVL(SQL_ID, S.PREV_SQL_ID) SQL_ID FROM V$PROCESS P, V$SESSION S WHERE P.ADDR = S.PADDR AND S.STATUS = 'ACTIVE' AND P.BACKGROUND IS NULL; 等待事件sga:allocation forcing component growth 20200217: 今天安装redis时发现一些语法比较奇怪的脚本,上网查了一下,原来是tcl脚本 百度了一下,介绍这样的:“Tcl 是一种 脚本语言。 由John Ousterhout建立。 TCL很好学,功能很强大。TCL常常被用于 快速原型开发,脚本编程, GUI和测试等方面。”,TCL念做“踢叩” "tickle" 之后有机会要了解一下 20200220: make install时能够临时指定安装目录,make PREFIX=/home/huangcihui/local install 20200225: 今天测试redis性能时偶然发现redis服务设置了密码,但运行redis-benchmark时没输入密码参数结果也能跑成功。 后来研究了一下代码才发现,redis-benchmark工具默认对返回结果不作检查,须要加上-e参数,才会检查redis命令执行结果是否成功。 20200228: 今天发如今高并发状况下,oracle的merge语句也可能会出现主键冲突。以前在低并发状况时一直用merge一次完成INSERT+UPDATE,避免主键冲突。 20200229: 今天同事反映,生产上有一些交易被拒绝,报20200229日期非法。但今年是闰年,理论上不该该出现这个问题,并且奇怪的是否是全部交易都被拒绝。后来查了一下代码,里面有这样的代码: char year[5]; strcpy(year, dateTime, 4); if (IsLeap(atoi(year)) { ... } 因而明白了,程序里面对于year没有作初始化,致使有时atoi结果出现异常,致使程序判断闰年错误。 20200302: ps aux www|grep -E 'TTY|redis',这样能够保留ps输出的标题 201200303: 当你使用sudo去执行一个程序时,处于安全的考虑,这个程序将在一个新的、最小化的环境中执行,也就是说,诸如PATH这样的环境变量,在sudo命令下已经被重置成默认状态了。 要想改变PATH在sudo会话中的初始值,用文本编辑器打开/etc/sudoers文件,找到”secure_path”一行,当你执行sudo 命令时,”secure_path”中包含的路径将被当作默认PATH变量使用。 sudo -v 延长密码有效期限5分钟,这样就能够临时省去sudo输入密码的麻烦 20200304: redhat的屏保竟然是向上拖动的,不是像windows同样点击自动消失的。 开机后等很久一直停留在时间界面,点了没反应,我一直觉得开机没完成。。。 20200305: 新安装的redhat默认启动是进入图形界面,能够执行命令 systemctl set-default multi-user.target,这样重启后优先进入命令行界面 若是之后须要恢复回来,则执行systemctl set-default graphical.target便可 临时命令行切换至桌面命令: init 5 临时桌面切换至命令行命令: init 3 20200308: redhat配置网卡自动链接,并使用dhcp配置网络地址方法: 须要修改配置/etc/sysconfig/network-scripts/ifcfg-<网卡名称> 假设网卡名字叫eth0,则修改/etc/sysconfig/network-scripts/ifcfg-eth0 将BOOTPROTO改成dhcp,ONBOOT改成yes 修改后使用ifup eth0启动链接