mysql-使用联合索引

背景

项目使用mysql数据库,某张表数据量2000W左右,比较大,在组合查询时发生超时,需要优化。

优化

查询优化常用方法就是建立索引

查询语句样例:查询在20181001-20181010时间范围内A=a且B=b的数据

select * from table where A = 'a' and B = 'b' and Date > '20181001' and Date < '20181010'

按照查询建立了一个组合索引 idx_query(A, B, Date),查询仍然报超时。然后开始研究索引原理,最后更改索引中列的顺序为idx_query(B,A,Date)解决。

---------------------------------------------------------------------------------------------

上面只是简单的项目背景,下面从原理细细解读索引

索引原理

首先,出问题以后再建立索引,是一种不好的习惯。排查、定位、解决问题会耗费很多开发时间和精力。

当然,不充分思考就给大多数列建立单列索引,给所有查询建立联合索引,是一种更坏的习惯。毕竟删除索引风险远高于添加索引。

使用索引需要成本:

  • 空间成本:索引是占空间的,大表的联合索引占用空间不可忽略
  • 时间成本:使用不对的索引会浪费时间
  • 更新成本:增删改操作只要跟索引有关系,就需要更新索引

索引适合在返回大表中很小一部分数据时使用,很小当然越小越好,5%以下还可以,1%以下更好,如果表的数据量非常大,千万级别,返回行数要小到0.1%以下

从很大表中用联合条件查询出很小的数据,等价于count(distinct 联合条件) 的值很大,这个值被称为Cardinality,索引适合度=Cardinality/表记录数。

索引误区

多个单列索引(如idx_A, idx_B)不等同于联合索引(idx_A_B)

两个联合索引里的列顺序不同,这两个联合索引也不等价,适用场景不同

联合索引idx_A_B能够覆盖的场景

  • A = ? and B = ?
  • A = ? and B in (?, ?, ?)
  • A = ?
  • A in (?,?,?)

覆盖场景可以根据索引存储结构(B+Tree)推导出。

上面罗列的几种覆盖场景,效率由上至下越来越低,因为扫描行数越来越大

联合条件中,最左侧的索引列很重要,最好使用Cardinality最大的列。

总结

项目中遇到的问题,最终根据索引原理中 最左侧索引列使用Cardinality最大列 解决。

苹果Magic Mouse修复

苹果Magic Mouse已经损坏了好长时间了,故障现象就是鼠标无法移动,但是点击,触摸都是有效的。网上搜索了一下,貌似这种故障很多。

大概率是Apple设计原因导致的故障。原因在于这个芯片跟罗技的鼠标用的同一个型号的,而罗技的鼠标很少发生类似的故障。初步猜测是Apple设计的时候,地线是跟外壳联通的,导致静电会沿着金属外壳击穿芯片内部管脚。

继续阅读苹果Magic Mouse修复

使用java获取当前是星期几

有个小需求,获取今天是周几,想我大java,获取一个星期几不是手到擒来。

第一想法,System.currentTimeMillis(),这是个时间戳,还得处理秒数,太麻烦。

第二想法,new Date() deprecated?  好吧。

第三想法,Calendar,简单写下代码,开始调试

weekDay = 3,wtf?今天是周二,怎么给了我一个3,只听说过从0、1计数,没听说过从2开始计数的啊!

继续查

国际上是以星期日为一周第一天的开始,Calendar中提供的DAY_OF_WEEK获取的一周也是以星期日作为一周的开始。

而中国的习惯是以星期一作为一周的开始,所以需要根据项目的实际需求来设置。

好吧,真是人生处处皆学问,写代码还能学知识。

怎么办呢?Calendar有个api叫setFirstDayOfWeek,原来从哪一天开始是可以设置的,java也是蛮人性化的么~

继续调试

weekDay = 3

这就有点意思了,这个api是用来看的么? 继续查

官方文档一大堆,概括为:

setFirstDayOfWeek的方法意思只对WEEK_OF_MONTH WEEK_OF_YEAR 有作用.

WEEK_OF_MONTH :当前Calendar日期对象是当前月的第几周.

WEEK_OF_YEAR :当前Calendar 日期对象是当前年的第几周.

好吧,老老实实写下比较丑陋的代码

最低成本解决招商银行香港网银账户长时间不交易被冻结的问题

最近收到招商银行香港银行的短信:

查询了一下,根据香港的规定,"账户连续两年内没有任何主动交易,则账户自动转为冻结状态,成为“睡眠户”,该类账户不允许进行出款交易。若您需要重新恢复该账户的使用,需要您填妥解除睡眠户表格寄送给香港分行审批,审批通过后,香港分行会主动联系您,核实后可以解除。"

以前总是傻傻的进行一次国内的转账操作,每次都被收高昂的手续费。今天终于想明白了,只要进行交易都算,那么干脆做一笔最小的活期转定期的存款,比如100块美金的一周定期,就搞定了。

最近(2021/03),上述的办法已经不行了,最近会收到如下信息:

比较简单的方式是找同事要一下账号,同行转出1分钱即可,也可以给慈善机构捐款,还是转账一分钱最简单。

另外,若网银每日限额已经被清零,可能收到如下短信通知:

可以登录香港专业版,可以使用“复原网银限额”复原到最近一次的网银限额;只有一个月内复原,才有效果。

PLMN概念和应用设置

PLMN

PLMN(Public Land Mobile Network,公共陆地移动网络)

该网路必须与公众交换电话网(PSTN)互连,形成整个地区或国家规模的通信网。

PLMN = MCC + MNC

中国移动的PLMN为46000,46002,46007

中国联通的PLMN为46001,46006

中国电信的PLMN 46003,46005

 

PLMN的分类 

对于一个特定的终端来说,通常需要维护几种不同类型的PLMN列表,每个列表中会有多个PLMN。

  RPLMN(Registered PLMN 已登记PLMN):

已登记PLMN。是终端在上次关机或脱网前登记上的PLMN。

在3GPP 2003年第TSG TP-21次会议上决定,将该参数从USIM卡上删掉,而将其保存在终端的内存中。

  EPLMN(Equivalent PLMN 等效PLMN):

为与终端当前所选择的PLMN处于同等地位的PLMN,其优先级相同。

  EHPLMN(EquivalentHome PLMN等效本地PLMN):

为与终端当前所选择的PLMN处于同等地位的本地PLMN。

其实:EHPLMN和EPLMN就好比是中移动的新建的158网络,

而EPLMN就好比是原来的135~139网络。

  HPLMN(Home PLMN 归属PLMN):

为终端用户归属的PLMN。也就是说,终端USIM卡上的IMSI号中包含的MCC和MNC与HPLMN上的MCC和MNC是一致的,

对于某一用户来说,其归属的PLMN只有一个。

  VPLMN(Visited PLMN 访问PLMN):

为终端用户访问的PLMN。其PLMN和存在SIM卡中的IMSI的MCC,MNC是不完全相同的。当移动终端丢失覆盖后,一个VPLMN将被选择。

  UPLMN(User Controlled PLMN 用户控制PLMN):

是储存在USIM卡上的一个与PLMN选择有关的参数。

  OPLMN(Operator Controlled PLMN 运营商控制PLMN):

是储存在USIM 卡上的一个与PLMN选择有关的参数。

  FPLMN(Forbidden PLMN禁用PLMN):

为被禁止访问的PLMN,通常终端在尝试接入某个PLMN被拒绝以后,会将其加到本列表中。

  APLMN(Approve PLMN 可捕获PLMN):

为终端能在其上找到至少一个小区,并能读出其PLMN标识信息的PLMN。

PLMN的选择优先级:

不同类型的PLMN其优先级别不同,终端在进行PLMN选择时将按照以下顺序依次进行:

RPLMN

EPLMN

HPLMN

EHPLMN

UPLMN

OPLMN

其他的PLMN

From:      http://baike.baidu.cn/view/544151.htm

 

3GPP 23122协议规定的小区重选PLMN选择顺序

3GPP 23122协议规定的小区重选PLMN选择顺序

At switch on or recovery from lack of coverarge,用户首先尝试选择的是RPLMN(registered PLMN),选择失败后按照如下顺序选择:

1)         HPLMN(如果EHPLMN列表不存在或为空)或最高优先级的EHPLMN(如果EHPLMN列表存在);

2)         在SIM卡数据中按照UPLMN优先级顺序选择;(User Controlled PLMN Selector with Access Technology)

3)         在SIM卡数据中按照OPLMN优先级顺序选择;(Operator Controlled PLMN Selector with Access Technology)

4)         随机选择RSCP值大于-84dBm(足够强度信号质量)形成的PLMN接入技术组合;

5)         当信号强度不够时,根据接收信号强度递减排序选择其他所有PLMN。

From:      http://blog.sina.com.cn/s/blog_6617106b01013nxi.html

 

手机PLMN相关处理

因为有多个PLMN,USIM卡中存储的的EHPLMN List用支持多个HPLMN lists;

对于2G SIM卡中是不存在EHPLMN List存储区域。

手机支持从UICC卡文件系统中读取EHPLMN List,只有在UICC文件系统支持EHPLMN List的情况下。

而EHPLMN List就是决定手机支持的PLMN;对SIM卡没有EHPLMN List,而只有HPLMN即IMSI一个;会将HPLMN作为终端的PLMN.

当SIM卡的PLMN事46002,而手机注册的基站网络PLMN是46000;将会是一种漫游状态;而实际上不是。

 

鉴于这个问题,手机方案厂商采取一些措施解决:

高通将EHPLMN List可存储在手机内存上;2G卡将从手机内存中读取EHPLMN List,USIM或从卡中读取;

需要设置NV:

NV65602:Location – /nv/item_files/modem/nas/ehplmn

Default value – 0x03 0x64 0xf0 0x00 0x64 0xf0 0x20 0x64 0xf0 0x70 (46000, 46002, 46007)

 

NV70189:Location – /nv/item_files/modem/nas/ tdscdma_op_plmn_list

Default value – 0x03 0x64 0xf0 0x00 0x64 0xf0 0x20 0x64 0xf0 0x70 (46000, 46002, 46007)

Modem代码中处理与PLMN相关的函数:

reg_sim.c :reg_sim_read_ehplmn_list

参考链接


PLMN概念和应用设置

ubuntu 16.04防止SSH暴力登录攻击

最近观察服务器的认证日志,发现有些国外的IP地址,多次尝试破解服务器的密码进行登录。于是希望能将多次尝试 SSH 登录失败的IP阻止掉。

查看日志文件:

看到很多如下的日志:

Failed password for root from 123.15.36.218 port 51252 ssh2
reverse mapping checking getaddrinfo for pc0.zz.ha.cn [218.28.79.228] failed – POSSIBLE BREAK-IN ATTEMPT!
Invalid user akkermans from 218.28.79.228
pam_unix(sshd:auth): check pass; user unknown
pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=218.28.79.228

来统计一下有多少人在暴力破解 root 密码

如果已经禁用了root登录,则看一下暴力猜用户名的统计信息

某个人尝试了 129 次。为了防范于未然,我们可以做些配置,让服务器更加安全。

下面的三个方法,可以完全使用,也可以部分使用。一般建议使用其中的第一条跟第三条。

1. 修改 SSH 端口,禁止root 登陆

修改/etc/ssh/sshd_config文件

2. 禁用密码登陆,使用 RSA 私钥登录

如果服务器只允许使用私钥登录的,但是如果想在别的电脑上临时SSH上来,又没带私钥文件的情况下,就很麻烦。所以还是保留密码验证登录。不管怎样,这一条还是先列出来

3. 安装 denyhosts

denyhostsPython 语言写的一个程序,它会分析 sshd 的日志文件,当发现重复的失败登录时就会记录 IP/etc/hosts.deny 文件,从而达到自动屏 IP 的功能。现今 denyhosts 在各个发行版软件仓库里都有。

注意在 ubuntu 16.04 系统上,如果通过远程的 SSH 登录到服务器上执行安装命令的话,会由于默认情况下 RESET_ON_SUCCESS = yes #如果一个ip登陆成功后,失败的登陆计数是否重置为0 这部分,默认情况下是关闭的。而如果恰好我们又出现自己输入的错误密码错误累计次数超过 5 次的情况(即使后面有成功登录的记录也不行),会导致我们自己当前登录的地址也被阻止的情况。这种情况发生之后,会导致我们自己无法控制服务器(这个阻塞是在 iptables 层阻塞的,如果要恢复,在 iptables 中删除已经添加的记录才可以)。解决办法就是换一个新的 IP 地址登录服务器,然后修改 RESET_ON_SUCCESS 这个参数,并重启 denyhosts 服务。如果是阿里云或者腾讯云的服务器,可以尝试从他们网站上提供的网页版本的 Shell 进行操作。

对于 ubuntu 16.04 系统,建议使用如下方式进行安装:

默认配置就能很好的工作,如要个性化设置可以修改 /etc/denyhosts.conf

查看 /etc/hosts.deny 发现里面已经有 3 条记录。

目前 ubuntu 16.04 系统源里的 denyhosts 存在一个 BUG ,就是系统重启之后,iptables 中的拦截设置没有恢复。具体的讨论以及描述,参考Iptables not persistent,代码应该已经增加了,目前还没合并到主分支。

对于 ubuntu 20.04 系统,默认源已经不包含 denyhosts ,需要使用 Fail2ban 替代。参考 How to Install and Configure Fail2ban on Ubuntu 20.04

参考链接


ThinkPad-T440通过U盘启动的方式升级BIOS

最近在ThinkPad-T440上安装最新的Ubuntu 17.04的时候,系统提示如下信息:

通过提示,可以看到是系统的CPU微码部分没有更新到最新,导致系统在执行部分功能的时候发生了异常,升级BIOS可以解决这个问题。

在联想官网上下载最新的BIOS光盘镜像(假定镜像名为BIOSCD.iso之后,发现无法直接通过U盘启动系统。原因是光盘的镜像格式不符合U盘启动需要的格式,需要进行转换之后才可以正常启动系统。

可以通过如下的方式,转换下载到的镜像文件之后,刷新BIOS

之后,重启系统即可。

继续阅读ThinkPad-T440通过U盘启动的方式升级BIOS

CVR100W升级到最新固件1.0.1.24

家里用的CVR100W路由是几年前买的,当时升级过一次固件,版本到1.0.1.19,但是最近几个月发现出现了无线不稳定的情况,有线访问打开路由器主页也变得比较慢,重启无效。因此怀疑是路由器系统在长时间运行后,这个版本的固件是存在问题的。

去思科官网搜索一下最新固件,竟然看到了1.0.1.24版本的固件,于是下载下来CVR100W_FW_1.0.1.24,各位也可以去思科官网去搜索下载。

目前测试来看,这个版本的固件应该是更稳定,速度也有所提升。
继续阅读CVR100W升级到最新固件1.0.1.24