mysql 关联查询 索引不起作用原因记录

今天联表查询的时候发现,两个表的’openid’都已经加了索引,联表的使用也是用的索引字段,理论上应该能命中索引,但是explain分析索引失效了,导致查询平均时间从0.01暴涨到平均十几秒

SELECT l.*,m.nickname,m.id AS member_id,m.mobile,m.avatar,m.realname,m.weixin,m1.nickname AS m1_nickname,m1.id AS m1_id,m1.mobile AS m1_mobile,m1.avatar AS m1_avatar,m1.realname AS m1_realname,m2.nickname AS m2_nickname,m2.id AS m2_id,m2.mobile AS m2_mobile,m2.avatar AS m2_avatar,m2.realname AS m2_realname,ml.logno,ml.createtime AS rechargetime,ml.rechargetype FROM `ims_vcshop_reward` l LEFT JOIN `ims_vcshop_member` m ON l.openid=m.openid LEFT JOIN `ims_vcshop_member` m1 ON l.m1=m1.id LEFT JOIN `ims_vcshop_member` m2 ON l.m2=m2.id LEFT JOIN `ims_vcshop_member_log` ml on ml.id=l.logid WHERE l.uniacid=2  ORDER BY l.id DESC limit 0,50

修改后命中索引

最后通过百度大法发现
1、两表关联使用的条件字段中字段的长度是否是一致的(本人测试不影响,规范期间数据库相同字段还是要保持长度一致)

2、两表关联使用的条件字段中字段的编码是否是一致的

如果以上两种情况不满足,也会导致索引失效;
本人在此就是’openid’字段,分别使用了utf8和utf8mb4两种编码,导致索引失效;

Mysql 5.7 5.6 5.5新增保留字

Mysql5.6新增保留字

GET IO_AFTER_GTIDS IO_BEFORE_GTIDS
MASTER_BIND ONE_SHOT PARTITION
SQL_AFTER_GTIDS SQL_BEFORE_GTIDS

Mysql5.7新增保留字

ACCOUNT ALWAYS CHANNEL
COMPRESSION ENCRYPTION FILE_BLOCK_SIZE
FILTER FOLLOWS GENERATED (R)
GROUP_REPLICATION INSTANCE JSON
MASTER_TLS_VERSION NEVER OPTIMIZER_COSTS (R)
PARSE_GCOL_EXPR PRECEDES REPLICATE_DO_DB
REPLICATE_DO_TABLE REPLICATE_IGNORE_DB REPLICATE_IGNORE_TABLE
REPLICATE_REWRITE_DB REPLICATE_WILD_DO_TABLE REPLICATE_WILD_IGNORE_TABLE
ROTATE STACKED STORED (R)
VALIDATION VIRTUAL (R) WITHOUT
XID

MySql 使用CASE WHEN语法条件性处理数据

假设数据库有字段 id,money1,money2,m1,m2,查询时需要判断mid=m1则累计money1,mid=m2则累计money2,此时可以使用CASE WHEN语法条件性处理数据

SELECT SUM(
    CASE WHEN m1=:id THEN money1 WHEN m2=:id THEN money2 ELSE 0 END
) AS money FROM TABLE
# Tips:匹配m1=:id时,返回money1;匹配m2=:id时,返回money2,否则返回0

DenyHost 预防SSH暴力破解

DenyHosts安装及配置

一、DenyHost简介
DenyHosts是Python语言写的一个程序软件,运行于Linux上预防SSH暴力破解的,它会分析sshd的日志文件(/var/log/secure),当发现重复的攻击时就会记录IP到/etc/hosts.deny文件,从而达到自动屏IP的功能。
官网地址:http://denyhosts.sourceforge.net/
DenyHosts安装包下载地址:https://sourceforge.net/projects/denyhosts/files/
二、安装过程

tar zxvf DenyHosts-2.6.tar.gz                             #解压源码包
cd DenyHosts-2.6                                          #进入安装解压目录
python setup.py install                                   #安装DenyHosts
cd /usr/share/denyhosts/                                  #默认安装路径
cp denyhosts.cfg-dist denyhosts.cfg                       #denyhosts.cfg为配置文件
cp daemon-control-dist daemon-control                     #daemon-control为启动程序
chown root daemon-control                                 #添加root权限
chmod 700 daemon-control                                  #修改为可执行文件
ln -s /usr/share/denyhosts/daemon-control /etc/init.d     #对daemon-control进行软连接,方便管理

安装到这一步就完成了。
/etc/init.d/daemon-control start                          #启动denyhosts
chkconfig daemon-control on                               #将denghosts设成开机启动

三、配置文件简要说明

vim /usr/share/denyhosts/denyhosts.cfg        #编辑配置文件,另外关于配置文件一些参数,通过grep -v "^#" denyhosts.cfg查看
SECURE_LOG = /var/log/secure                  #ssh 日志文件 #redhat系列根据/var/log/secure文件来判断;
                                                           #Mandrake、FreeBSD根据 /var/log/auth.log来判断;
                                                           #SUSE则是用/var/log/messages来判断,这些在配置文件里面都有很详细的解释。
HOSTS_DENY = /etc/hosts.deny                  #控制用户登陆的文件
PURGE_DENY = 30m                              #过多久后清除已经禁止的,设置为30分钟;
# ‘m’ = minutes
# ‘h’ = hours
# ‘d’ = days
# ‘w’ = weeks
# ‘y’ = years
BLOCK_SERVICE = sshd                         #禁止的服务名,当然DenyHost不仅仅用于SSH服务
DENY_THRESHOLD_INVALID = 1                   #允许无效用户失败的次数
DENY_THRESHOLD_VALID = 3                     #允许普通用户登陆失败的次数
DENY_THRESHOLD_ROOT = 3                      #允许root登陆失败的次数
DAEMON_LOG = /var/log/denyhosts              #DenyHosts日志文件存放的路径,默认

更改DenyHosts的默认配置之后,重启DenyHosts服务即可生效:
/etc/init.d/daemon-control restart         #重启denyhosts

监控非SSH服务
需要添加正则匹配,官方文档有说明。

相似工具
Fail2Ban,使用iptables
BlockHosts
Blacklist

SSH安全配置
PermitRootLogin no
PasswordAuthentication no
Port 59922

参考文章:https://www.cnblogs.com/lcword/p/5912625.html

防止ssh暴力破解,自动提交黑名单

近日系统发现多例ssh登录失败记录,明显是有人ssh暴力破解,百度了下[1]参考,做了以下处理
一、系统:Centos

二、方法:读取/var/log/secure,查找关键字 Failed,例如(注:文中的IP地址特意做了删减):

Sep 17 09:08:09 localhost sshd[29087]: Failed password for root from 13.7.3.6 port 44367 ssh2
Sep 17 09:08:20 localhost sshd[29087]: Failed password for root from 13.7.3.6 port 44367 ssh2
Sep 17 09:10:02 localhost sshd[29223]: Failed password for root from 13.7.3.6 port 56482 ssh2
Sep 17 09:10:14 localhost sshd[29223]: Failed password for root from 13.7.3.6 port 56482 ssh2

从这些行中提取IP地址,如果次数达到10次(脚本中判断次数字符长度是否大于1)则将该IP写到 /etc/hosts.deny中。

三、步骤:

1、先把始终允许的IP填入 /etc/hosts.allow ,这很重要!比如:
sshd:19.16.18.1:allow
sshd:19.16.18.2:allow

2、脚本 /usr/local/bin/secure_ssh.sh

#! /bin/bash
cat /var/log/secure|awk '/Failed/{print (NF-3)}'|sort|uniq -c|awk '{print2"="1;}'>/usr/local/bin/black.list
for i in `cat  /usr/local/bin/black.list`
do
  IP=`echoi |awk -F= '{print 1}'`
  NUM=`echoi|awk -F= '{print 2}'`
  if [{#NUM} -gt 1 ]; then
    grep IP /etc/hosts.deny>/dev/null
    if [? -gt 0 ];then
      echo "sshd:$IP:deny" >> /etc/hosts.deny
    fi
  fi
done

3、将secure_ssh.sh脚本放入cron计划任务,每1分钟执行一次。

crontab -e

*/1 * * * * sh /usr/local/bin/secure_ssh.sh


这样脚本检查到暴力破解ip就会自动提交到黑名单禁止访问
最后做出总结:
– 修改默认22端口
– 禁止root用户登录,使用其他用户操作root命令[2]
– 使用秘钥登录ssh,不使用密码登录
– 添加上诉脚本自动提交黑名单,封禁IP

PHP session 存储方式

PHP session 存储方式有3种

1)文件存储,file

2)memcahe存储

3)redis存储


1)file(默认方式)

session.save_handler = file  
ssession.save_path = "/tmp"  

第一点设置为使用文件存储session,第二点为默认的存储位置

 


2)memcache

session.save_handler = memcache  
session.save_path = "tcp://127.0.0.1:11211,tcp://Mem服务器2:端口号..."  

使用多个 memcached server 时用逗号","隔开,可以带额外的参数"persistent"、"weight"、"timeout"、"retry_interval" 等,  
类似:"tcp://host1:port1?persistent=1&weight=2,tcp://host2:port2"  
参考:http://php.net/manual/zh/memcache.addserver.php  

如果安装的PECL是memcached(使用libmemcache库的那个),则配置应为  
ini_set("session.save_handler", "memcached"); // 是memcached不是memcache  
ini_set("session.save_path", "127.0.0.1:11211"); // 不要tcp://  
参数参考:http://php.net/manual/zh/memcached.addserver.php  

 


3)redis

session.save_handler = redis  
session.save_path = "tcp://host1:6379?weight=1, tcp://host2:6379?weight=2&timeout=2.5, tcp://host3:6379?weight=2"  

参数:  
weight 比重  
timeout 超时  
persistent 持久连接 取值 0 1  
prefix session id 前缀  
auth 验证  
database 选择的数据库  

session 以秒表示 生命周期由session.gc_maxlifetime来控制  
ini_set('session.gc_maxlifetime','3600')可改变生存时间,需要SETEX 命令,redis版本至少2.0  

phpredis 也可以链接一个unix domain socket :unix:///var/run/redis/redis.sock?persistent=1&weight=1&database=0  

 


redis实例

ini_set('session.save_handler', 'redis');  
ini_set('session.save_path', 'tcp://127.0.0.1:6379');  
session_start();  
_SESSION['sessionKey'] = 'redis session!';  
var_dump(_SESSION['sessionKey']);  
echo '<br/>';  

redis = new redis();redis->connect('127.0.0.1', 6379);  
//redis用session_id作为key并且是以string的形式存储  
var_dump($redis->get('PHPREDIS_SESSION:' . session_id()));  

参考至https://blog.csdn.net/qq_39780174/article/details/78482943

利用阿里云周边实现SLB+ECS+NAS+RDS负载均衡高并发架构

基本思路:

1.创建自定义专有网络VPC,后续负载均衡SLB、服务器ECS、云数据库RDS都使用同一VPC

2.购买SLB

3.购买ECS一台,记得使用自建专有网络VPC,且不搭建公有网络

4.使用SLB对ECS进行4层协议,监听端口转发到ECS实例1,可访问公网

5.搭建ECS实例1环境,并购买文件存储包,进行快照,创建自定义镜像

6.购买相同配置ECS一台,使用刚才的自定义镜像创建环境

7.使用SLB对两台ECS进行7层协议,监听80端口,实行负载均衡

8.分别对两台ECS实例挂载共享数据盘NAS,并设置自动挂载

9.购买RDS-mysql版本,申请公网地址用于开发,并创建只读实例,使用读写分离地址用于程序

10.在实例1上安装应用程序,程序放置于NAS挂载点上,并把nginx配置复制到实例2上面

11.使用了负载均衡后,会遇到会话保持问题,此时需要做session共享,session共享有3种方式,这里使用第一种

1)利用NAS系统,修改session文件存储位置,存放到共享NAS系统中

2)使用memcache来做共享

3)使用redis来做共享

 

感谢标杆徐教学视频指导 http://medu.51cto.com/course/index/view?id=16806

SVN:checkout时地址错误

SVN:

checkout时显示”执行上下文错误: 由于目标计算机积极拒绝,无法连接。”或者显示no repository found in svn……..

都是因为客户端的版本库URL地址写错了

 

正确的格式应该是svn://ip:port/项目文件夹

如svn://127.0.0.1:3690/aaa

其中项目文件夹对应在服务器端svn注册的地址,如果不确定服务器端注册的地址

可以在linux中,先运行命令:killall svnserve,杀掉svn

然后重新注册svn地址

例如服务器端的svb仓库地址为/opt/svn/

则注册该地址,运行命令:svnserve -d -r /opt/svn/

此时服务器端地址已经注册成功

 

然后回到客户端重新填写地址即可

例如需要checkout项目app,路劲为/opt/svn/app

只需要填写svn://ip:port/app即可

tips:一般svn端口都为3690,例如svn://ip:3690/app

 

 

无限分类-树形结构两种方式

//准备数组,代替从数据库中检索出的数据(共有三个必须字段id,name,pid) 
header("content-type:text/html;charset=utf-8"); 
categories = array( 
 array('id'=>1,'name'=>'电脑','pid'=>0), 
 array('id'=>2,'name'=>'手机','pid'=>0), 
 array('id'=>3,'name'=>'笔记本','pid'=>1), 
 array('id'=>4,'name'=>'台式机','pid'=>1), 
 array('id'=>5,'name'=>'智能机','pid'=>2), 
 array('id'=>6,'name'=>'功能机','pid'=>2), 
 array('id'=>7,'name'=>'超级本','pid'=>3), 
 array('id'=>8,'name'=>'游戏本','pid'=>3), 
); 

/*方法1 利用引用*/
/*第一步 先组建以id为key的数组*/tree = array();
foreach(categories asv){
  tree[v['id']] = v;tree[v['id']]['children'] = array();
}
/*第二部 利用引用,将children添加进去,这样只遍历一次即可*/
foreach(tree as key=>v){
  if(v['pid'] != 0){tree[v['pid']]['children'] = &tree[key];//注意:此处必须传引用否则结果不对
  }
}
/*第三部 删除无用的根节点*/
foreach(tree as key=>v){
  if(v['pid'] !=0 ){
    unset(tree[key]);
  }
}


/*方法2 利用递归*/
function get_attr(arr,pid){tree = array();
  foreach(arr askey=>v){
    if(v['pid'] == pid){v['children'] = get_attr(arr,v['id']);
      if(empty(v['children'])){
        unset(v['children']);//如果为空,则删除,可选
      }
      tree[] =v;
    }
  }
  return tree;
}tree2 = get_attr($categories, 0);