博客 (56)

于 2024 年 8 月:

查看空间占用

  • 主菜单“云数据库 RDS” - 选择相应实例 - 自治服务 - 一键诊断 - 空间分析 - 立即分析 - 几分钟后就能看到报表(经济版 / 企业版可以开启自动分析)

  • 如果没有可清理的空间,可以直接扩容(有条件):实例 - 基本信息 - 变更配置 - 立即升配

慢查询(索引优化建议)

  • 主菜单“云数据库 RDS” - 选择相应实例 - 自治服务 - 慢SQL


2019 年 5 月前:

查看空间占用

  • 主菜单“云数据库 RDS 版” - 选择相应实例 - 二级菜单“CloudDBA” - 空间管理

  • 主菜单“混合云数据库管理 HDM” - 选择相应实例 - 二级菜单“库表空间” - 数据空间

注意“数据空间”只是数据的大小,跟磁盘占用有直接关系的是“表空间”,某些表(如日志表)记录频繁插入删除的,表空间会比较大,应执行“优化表(OPTIMIZE TABLE)”,优化过程中会影响表的写操作


慢查询(索引优化建议)

  • 主菜单“云数据库 RDS 版” - 选择相应实例 - 二级菜单“CloudDBA” - 性能优化

  • 主菜单“混合云数据库管理 HDM” - 选择相应实例 - 二级菜单“请求分析” - 慢日志


xoyozo 6 年前
7,570
二维码类型可扫码授权的微信号
其它微信号
直接扫码将二维码截图发送给可扫码授权的微信号无需劳烦管理员的方式
登录微信公众平台管理员与运营者

扫码后需管理员验证登录(管理员通过“公众平台安全助手”接收消息,点开详情后点击“确定”)

授权人用摄像头扫码,点击“确定”
成为运营者
设置公众号IP白名单管理员与长期运营者无法完成授权人用摄像头扫码,点击“确定”
成为长期运营者
公众号绑定运营者管理员无法完成管理员用摄像头扫码,点击“确定”

小程序添加/删除项目成员

管理员无法完成管理员直接识别二维码,点击“确定”
小程序修改名称、修改简称、修改登录邮箱、修改密码管理员无法完成“修改简称”管理员用摄像头扫码,点击“确定”,其它未测
小程序修改业务域名
管理员、有“开发者”权限的项目成员无法完成授权人直接识别二维码,点击“确定”成为有“开发者”权限的项目成员
微信开放平台绑定小程序管理员无法完成管理员用摄像头扫码,点击“确定”

① 摄像头扫码:无法直接用“识别二维码”,必须把二维码发送到身边的其它设备,再使用手机摄像头完成扫码

② 成为运营者要求绑定银行卡;成为运营者将占用“微信号绑定的帐号”数量,详见说明。若达到上限,只有法定代表人可继续成为运营者。在公众号“公众平台安全助手”中可查询绑定的帐号。

另外:

  • 小程序添加/删除体验成员无须管理员授权

  • 如果管理员未关注公众号“公众平台安全助手”,待测……

xoyozo 6 年前
5,262

当我们用 ASP.NET Web API 作服务端接口时,如果客户端以 GET 方式请求的 URL 中,由于拼接错误导致“?”和“&”并列出现,会发生 400 Bad Request,那么需要在 IIS 中使用 URL 重写模块来纠正。

请求 URL 如:

http://www.abc.com/api/obj?&foo=bar

需要重写为:

http://www.abc.com/api/obj?foo=bar


打开 IIS 管理器中对应网站的 URL 重写

image.png


添加空白规则。

匹配的 URL 不包含域名,如上述 URL 则匹配的范围是:

api/obj

不包含我们要查找的字符串 ?&,所以此处模式只能匹配所有:

.*

又因为重定向路径中需要包含这部分,所以用括号包裹,即:

(.*)

image.png

继续添加条件匹配:

条件输入:{QUERY_STRING},表示匹配查询字符串,

匹配的部分是“?”后面的字符串:

&foo=bar

那么可以填写模式:

^\&.*

因为 & 后面的部分仍然需要使用,所以用括号包裹:

^\&(.*)

image.png

“操作”中选择类型“重定向”,URL 填写:

{R:1}?{C:1}

其中 {R:1} 指代 api/obj,{C:1} 指代 foo=bar

取消“附加查询字符串”前面的勾

重定向类型在测试时可以选择 302 或 307,没问题后选择 301。

image.png

完成。

最终我们可以在网站的配置文件 web.config 中看到:

<rewrite>
    <rules>
        <rule name="uni-app-h5-replace-q" stopProcessing="true">
            <match url="(.*)" />
            <conditions>
                <add input="{QUERY_STRING}" pattern="^\&amp;(.*)" />
            </conditions>
            <action type="Redirect" url="{R:1}?{C:1}" appendQueryString="false" redirectType="Temporary" />
        </rule>
    </rules>
</rewrite>

我们要把这段代码复制到开发环境源代码的 web.config 中,以免发布网站时将我们设置好的配置覆盖掉。

xoyozo 7 年前
9,394

在学习和使用 ASP.NET Web API 之前,最好先对 RESTful 有所了解。它是一种软件架构风格、设计风格,而不是标准。


推荐视频教程:https://www.imooc.com/learn/811

讲师:会飞的鱼Xia

需时:2小时25分


REST API 测试工具:

在 Chrome 网上应用店中搜索:Restlet Client

或网站 https://client.restlet.com


>>> 资源路径

SCHEME :// HOST [ ":" PORT ] [ PATH [ "?" QUERY ]]

其中 PATH 中的资源名称应该使用复数名词,举例:

GET https://xoyozo.net/api/Articles/{id}

POST https://xoyozo.net/api/Articles


>>> HTTP verb(对应 CURD 操作):

方法功能ASP.NET Web API 接口返回类型(一般的)
GET取一个或多个资源T 或 IEnumerable<T>
POST增加一个资源T
PUT修改一个资源T
DELETE删除一个资源void
PATCH更新一个资源(资源的部分属性)
HEAD获取报头
OPTIONS查询服务器性能或资源相关选项和需求


>>> 过滤信息:

如分页、搜索等


>>> 常用状态码:

200
OK
指示请求已成功
201
Created
资源创建成功(常见用例是一个 PUT 请求的结果)
202
Accepted
该请求已被接收但尚未起作用。它是非承诺的,这意味着HTTP中没有办法稍后发送指示处理请求结果的异步响应。
204
No Content
成功 PUT(修改)或 DELETE(删除)一个资源后返回空内容(ASP.NET Web API 中将接口返回类型设置为 void 即可)
400
Bad Request
服务器无法理解请求(如必填项未填、内容超长、分页大小超限等),幂等
401
Unauthorized
未授权(如用户未登录时执行了须要登录才能执行的操作),通俗地讲,是服务器告诉你,“你没有通过身份验证 - 根本没有进行身份验证或验证不正确 - 但请重新进行身份验证并再试一次。”这是暂时的,服务器要求你在获得授权后再试一次。
403
Forbidden
服务器理解请求但拒绝授权(是永久禁止的并且与应用程序逻辑相关联(如不正确的密码、尝试删除其它用户发表的文章)、IP 被禁止等),通俗地讲,是服务器告诉你,“我很抱歉。我知道你是谁 - 我相信你说你是谁 - 但你只是没有权限访问此资源。”
404
Not Found
找不到请求的资源(指资源不存在,如果找到但无权访问则应返回 403)
405
Method Not Allowed
请求方法被禁用(HTTP 动词)
500
Internal Server Error
服务器遇到阻止它履行请求的意外情况(如数据库连接失败)
503
Service Unavailable
服务器尚未准备好处理请求(常见原因是服务器因维护或重载而停机,这是临时的,可用于在单线程处理事务时遇到被锁定时的响应,如抽奖活动、抢楼活动,防止因并发导致逻辑错误)


>> 错误处理:

C# 例:throw new HttpResponseException(HttpStatusCode.NotFound);

PHP 例:throw new Exception('文章不存在', 404);


>>> 返回结果:

JSON/XML

不要返回密码等机密字段


>>> 其它:

身份验证窗口(浏览器弹窗,类似 alert,非页面表单),明文传输,安全性不高,不建议使用。实现:

在 Headers 中添加 Authorization:Basic “用户名:密码”的 Base64 编码


xoyozo 7 年前
4,796

〓 系统

功能命令--help示例
关机halt
halt
重启reboot
reboot
系统监视器top系统时间, 运行天数, 当前登录用户数, 系统负载
总进程数, 运行中的, 睡眠的, 停止的, 未响应的
Cpu(s):us 用户, sy 系统, ni XX, id 空闲, wa 等待, hi XX, si XX
Mem, 已使用, 空余, 缓冲
Swap, 已使用, 空余, 缓冲
快捷键:
M 按占内存排序
P 按占Cpu排序
1 显示每个 Cpu
k 杀死进程
q 退出
top
查看进程psaux
-ef
列出包含 java 的进程
ps aux |grep java 
ps -ef |grep java
查看内存及 Swap 用量free-b,-k,-m,-g 按单位显示free -m
查看系统时间date   显示 CST 时间
-R 显示时区
-u 显示 UTC 时间
date
查看硬件时间clock
clock
设置系统日期

date -s 月/日/年
设置系统时间

date -s 时:分:秒
将系统时间写入到硬件时间

clock -w
查看系统版本

cat /etc/*release
升级系统软件

yum update -y

〓 文件

功能命令--help示例
进入目录cd
cd .. # 上一层目录
cd /root # 根目录
列出目录ls白色:表示普通文件
蓝色:表示目录
绿色:表示可执行文件
红色:表示压缩文件
浅蓝色:链接文件
红色闪烁:表示链接的文件有问题
黄色:表示设备文件
灰色:表示其他文件
ls
创建目录mkdir
mkdir XXX
删除目录rm
rm -rf XXX
删除文件rm
rm XXX
复制文件cp
cp XXX YYY
复制目录cp-r 复制目录及目录内的所有项目
-v 详细显示进行的步骤
cp -rv XXX YYY
重命名文件mv-i: 若指定目录已有同名文件,则先询问是否覆盖旧文件;
-f: 在mv操作要覆盖某已有的目标文件时不给任何指示;
mv 源文件 目标文件
移动文件mvmv 一个或多个文件 目标目录
下载文件wget下载到当前目录wget http://XXX.tar.gz
计算文件/目录的磁盘用量du-a 不仅显示目录,同时显示文件
-h 容易阅读方式显示
--max-depth=N 可指定计算深度
du -ah --max-depth=1 | sort -n
查找文件find
find /home -name *.apk

〓 tar

功能命令--help示例
tartar-z 是否压缩
-c 打包
-x 解包
-v 详细地列出处理的文件
-f 
打包:tar -cvf abc.tar abc
解包:tar -xvf abc.tar
压缩打包:tar -zcvf abc.tar.gz abc
解压解包:tar -zxvf abc.tar.gz

〓 磁盘

功能命令--help示例
查看所有磁盘及分区fdisk -l
fdisk -l
查看当前挂载df-h 按可阅读的方式打印数值和单位
-T 显示文件系统类型
df -hT
管理磁盘分区fdisk /dev/***进入后的操作说明:
m 显示命令菜单
d 删除一个分区
n 创建一个分区(e 扩展分区;p 主分区)
t 改变分区ID
q 不保存退出
w 保存退出
fdisk /dev/vdb
格式化分区mkfs.*** /dev/***N
mkfs.xfs /dev/vdb1
挂载分区mount /dev/***N /***
mount /dev/vdb1 /www
卸载分区umount /dev/***N
umount /dev/vdb1
开机自动挂载vi /etc/fstab配置文档格式:设备 挂载点 文件系统类型 defaults 0 0打开:vi /etc/fstab
配置:/dev/vdb1 /www xfs defaults 0 0

〓 网络

功能命令--help示例
查看 IP 配置ifconfig
ifconfig
配置网卡 IP
配置文件目录:/etc/sysconfig/network-scripts/
配置文件格式:
DEVICE=eth0 / eth0:0 / ... # 在配置多线时若使用 cp 命令复制配置文件,必须修改此项以防止冲突
HWADDR=XX:XX:XX:XX:XX:XX # 网卡地址
TYPE=Ethernet # 以太网
UUID=********
ONBOOT=yes # 开机启动
NM_CONTROLLED=yes
BOOTPROTO=static # 使用静态 IP
IPADDR=192.168.1.2 # IP 地址
NETMASK=255.255.255.XXX # 子网掩码
GATEWAY=192.168.1.1 # 网关
DNS1=114.114.114.114
DNS2=8.8.8.8
vi ifcfg-XXXN(:N)
重启网卡
使配置生效service network restart

〓 防火墙

功能命令--help示例
配置 iptables
添加需要允许的端口的方法同 22 端口vi /etc/sysconfig/iptables
重启使配置生效

service iptables restart

〓 用户/权限

功能命令--help示例
添加用户useradd-g 组名 # 加入到该组
-s /bin/false #不允用户直接登录系统
useradd –g 组名 用户名 -s /bin/false
修改密码passwd
passwd 用户
查看所有用户

cut -d : -f 1 /etc/passwd 
查看可以登录系统的用户

cat /etc/passwd | grep -v /sbin/nologin | cut -d : -f 1
删除用户
-r, --remove                  remove home directory and mail spooluserdel 用户
添加用户组groupadd
groupadd 组名
为组添加用户(用户必须已存在)gpasswd
gpasswd -a 用户 组
将用户移出组gpasswd
gpasswd -d 用户 组
查看用户所属组groups
groups 用户
查看组中有哪些用户groupmems
groupmems -g 组 -l
更改文件/目录所有者chown-R 递归处理所有的文件及子目录chown -R 用户:组 ***
更改文件/目录权限chmod-R 以递归方式更改所有的文件及子目录chmod -R 777 ***

〓 vi 编辑器

功能命令--help示例
打开文件vi
vi XXX
进入编辑模式
按 a/i/o/Insert 等
进入末行模式/命令模式
按 Esc后:
:w 保存不退出
:q 退出(提示是否保存)
:wq 保存并退出
:w XXX 另存到文件 XXX
:q! 不保存退出

〓 计划任务

功能命令--help示例
设置计划任务crontab详细步骤见本页底部crontab -l # 查看计划任务
crontab -e # 编辑计划任务

〓 网站

功能命令--help示例
简单审查日志cat | grep
cat 日志文件 | grep 关键词1 | grep 关键词2 | more
日志分析goaccess
见下文

〓 goaccess

功能命令--help示例
安装yum install goaccess

日志格式NCSA Commbined Log Format
date_format %d/%b/%Y
log_format %h %^[%d:%^] "%r" %s %b "%R" "%u"
参数-f需要解析的日志文件
参数-e指定 IP 地址统计
参数-p指定配置文件可以将上面的日志格式内容保存到文件 ~/.goacessrc
参数-H显示 HTTP 协议信息
参数-M显示 HTTP 方法信息
生成文件

goaccess -f 日志文件 -p ~/.goaccessrc > 目标文件.htm

〓 lnmp

功能命令--help示例
重启 LNMP

/root/lnmp restart
重启 MySQL

/etc/init.d/mysql restart
重启 PureFTPd

/root/pureftpd restart
安装 LNMP
http://lnmp.org/install.html 
常见问题
http://lnmp.org/faq.html 
状态管理命令
http://lnmp.org/faq/lnmp-status-manager.html 
相关软件目录及文件位置
http://lnmp.org/faq/lnmp-software-list.html 
防跨站、跨目录安全设置(仅支持 PHP 5.3.3 以上版本)
http://www.vpser.net/security/lnmp-cross-site-corss-dir-security.html 
查看 Nginx 版本

nginx -V
查看 MySQL 版本

mysql -V
查看 PNP 版本

php -v
查看 Apache 版本

httpd -v
查内存

cat /proc/meminfo
php.ini

vim /usr/local/php/etc/php.ini
MySQL 配置文件

vim /etc/my.cnf
添加网站

/root/vhost.sh
添加 ProFTPd 用户

/root/proftpd_vhost.sh

〓 nginx

功能命令--help示例
启动/停止/重启service nginx

/etc/rc.d/init.d/nginx

service nginx start
service nginx stop
service nginx restart
伪静态在 .conf 文件中配置
rewrite ^(.*)/read-htm-(.*)\.html(.*)$ $1/read.php?$2.html? last;
rewrite ^(.*)/thread-htm-(.*)\.html(.*)$ $1/thread.php?$2.html? last;
rewrite ^(.*)-htm-(.*)$ $1.php?$2 last;
rewrite ^(.*)/simple/([a-z0-9\_]+\.html)$ $1/simple/index.php?$2 last;
rewrite ^(.*)/data/(.*)\.(htm|php)$ 404.html last;
rewrite ^(.*)/attachment/(.*)\.(htm|php)$ 404.html last;
rewrite ^(.*)/html/(.*)\.(htm|php)$ 404.html last;
防盗链在 .conf 文件中配置HttpRefererModule location ~* \.(gif|jpg|png|swf|flv)$
{
valid_referers none blocked *.0574bbs.com *.eyuyao.com 0574bbs.com eyuyao.com;
if ($invalid_referer)
{
rewrite ^/ http://web1.eyuyao.com/yyad/src/3122.jpg;
# return 404;
}
}
浏览器缓存在 .conf 文件中配置
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}

〓 vsftpd

功能命令--help示例
安装

yum install vsftpd
查看是否已安装

rpm -q vsftpd
启动/停止/重启service vsftpd
service vsftpd start
service vsftpd stop
service vsftpd restart
配置文件

vi /etc/vsftpd/vsftpd.conf

〓 MySQL

功能命令--help示例
登录mysql
mysql -u username -p
登出

exit
查看信息

status;
查询当前正在执行的 SQL 语句

show processlist;
删除指定时间之前的日志PURGE
PURGE MASTER LOGS BEFORE '2015-1-1 0:00:00';

〓 scp 远程文件/目录传输命令 (yum install openssh-clients) 用法

scp 会把文件权限(读取/写入/执行)带过来,但所有者为当前执行 scp 命令的用户。

scp 低版本有许多漏洞,用完最好 yum remove openssh-clients

scp 采用直接覆盖的机制,如需判断文件无差异则跳过,应改用 rsync 命令。查看 rsync 详细使用方式及与 scp 对比

功能命令--help示例
若远程服务器 SSH 端口非默认scp-P 端口号
下载远程服务器上的文件到本地scp
scp 远程用户@远程服务器:远程文件 本地文件
下载远程服务器上的目录到本地scp

-P 端口

-v 显示进度

-r 递归

scp -r 远程用户@远程服务器:远程目录 本地目录

实例:scp -r root@x.x.x.x:/a/b/ /c/d/

结果:/c/d/b/,即将整个 b 复制到 d 下(注意与 rsync 命令的区别)


本地文件上传到远程服务器scp
scp 本地文件 远程用户@远程服务器:远程文件
本地目录上传到远程服务器scp最终目录结构参:远程->本地scp -r 本地目录 远程用户@远程服务器:远程目录

〓 rsync 远程文件/目录传输命令 (yum install rsync) 用法查看 rsync 详细使用方式及与 scp 对比

rsync 会把文件权限(读取/写入/执行)带过来,所有者也会带过来。

相比于 scp 最大的优势就是可以增量同步

功能命令--help示例
下载远程服务器上的目录到本地rsync

-a 递归

-v 详细

-p, -- perms 保持权限

-g, -- group 保持属组

-o, --owner 保持属主

-r 递归

--progress 打印

--delete 删除已不存在的文件

-u 表示仅更新较新的文件

-z 表示在传输过程中进行压缩

-e 'ssh -p 2222' 指定其它端口

rsync 远程用户@远程服务器:远程目录 本地目录

实例:rsync -avu --progress root@x.x.x.x:/a/b/ /c/d/

结果:/c/d/,即将 b 内的文件(夹)复制到 d 下(注意与 scp 命令的区别)


本地文件上传到远程服务器rsync
rsync 本地文件 远程用户@远程服务器:远程文件
本地目录上传到远程服务器rsync最终目录结构参:远程->本地rsync 本地目录 远程用户@远程服务器:远程目录

〓 ftp 客户端 (yum install ftp)

功能命令--help示例
登录ftp
ftp 目标服务器
列出远程当前路径目录/文件ls
ls
创建远程目录mkdir
mkdir 目录名
删除远程目录(空)rmrmdir
mkdir 目录名
进入远程目录cd
cd 目录名
显示远程当前路径pwd
pwd
重命名远程文件rename
rename 原文件名 新文件名
上传文件put
put 本地文件名
下载文件get
get 远程文件名
批量下载文件mget需要单个确认
批量下载文件【lftp】mirror参数有很多mirror
返回 shell(不退出)!
!
返回 ftp(接上步)exit
ftp

exit
ftp
结束bye
quit

bye
quit

〓 iftop

流量监控工具 教程 

〓 GoAccess

实时网站日志分析工具 官网 

〓 Cacti

网络流量监测图形分析工具 官网  百科 

常见问题笔记

加硬盘

  • 插入新硬盘

  • 若有 RAID,则先设置,使操作系统能认到硬盘

  • 使用 fdisk 命令对新设备进行分区

  • 使用 mkfs 命令对新分区进行格式化

  • 使用 mount 命令进行挂载

  • 设置开机自动挂载(vi /etc/fstab)

更改 MySQL 数据库目录位置

  • 停止 MySQL 服务

  • 将原数据目录转移或复制到新位置(若是复制,则修改所有者使原来一致)

  • 找到 my.cnf 配置文件(一般在 /etc/),修改 datadir 值为新路径

  • 启动 MySQL 服务

502 Bad Gateway 问题排查

  • 查看 PHP 日志,路径:/usr/local/php/var/log

  • 一般为“server reached pm.max_children setting (10), consider raising it”连接数问题,在“/usr/local/php/etc”下的所有配置文件中查找并修改相关设置即可(如改成 1000)。

计划任务(实例:定时备份数据库并通过 FTP 同步至其它服务器)

  • 创建可执行文件:vi dotask.sh

  • dotask.sh 的内容示例:

    DATE_TIME=`date +%Y_%m_%d_%H%M%S`;
    FILE_NAME=数据库名_backup_$DATE_TIME.sql;
    cd /home/mysqlbackup/;
    mysqldump -u数据库用户名 -p数据库密码 数据库名>$FILE_NAME;
    tar -zcf $FILE_NAME.tar.gz $FILE_NAME;
    rm $FILE_NAME;

    ftp -v -n FTP地址 << END
    user FTP用户名 FTP密码
    bin
    put 本地目录文件 目标路径文件
    bye
    END


    文件名乱码问题可以在行末加“;”来解决

  • 赋予执行权限:chmod 777 dotask.sh (ls 命令时呈绿色)

  • 编辑计划任务:crontab -e

  • crontab 书写规则:

    # 分 时 日 月 周 文件路径
    0 3 * * * /home/dotask.sh
    30 4 * * * /home/dotask2.sh


    更多帮助 

  • 重启 crond:/etc/init.d/crond restart

netstat

  • netstat -an | grep xxx.xxx.xxx.xxx 可查看此 IP 的 TCP 请求及端口

xoyozo 7 年前
7,508

Discuz! 数据库加索引


待优化的 SQL:(pre_forum_thread 表有 150 万条数据)

SELECT * FROM pre_forum_thread  WHERE `fid`='62' AND `displayorder` IN('0','1','2','3','4')  ORDER BY displayorder DESC, dateline DESC    LIMIT 20, 20

加索引前,

EXPLAIN 结果 Extra 为:Using index condition; Using where; Using filesort

> 时间: 0.915s

加索引后:`fid`, `displayorder`, `dateline`

EXPLAIN 结果 Extra 为:Using where 或 Using index condition

> 时间: 0.001s


magapp 数据库加索引


待优化的 SQL:(mag_score_action_log 表有 200 万条数据)

SELECT COUNT(*) AS tp_count
FROM `mag_score_action_log`
WHERE action_id = 20
	AND user_id = 650070
	AND create_time >= 1534953600
	AND create_time < 1535040000
LIMIT 1

加索引前,

EXPLAIN 结果 Extra 为:?????

> 时间: 70s

加索引后:`action_id`, `user_id`, `create_time`

EXPLAIN 结果 Extra 为:Using where; Using index

> 时间: 0.073s



待优化的 SQL:(mag_score_mission_log 表有约 55 万条数据)

SELECT COUNT(*) AS tp_count
FROM `mag_score_mission_log`
WHERE mission_id = 7
	AND user_id = 650070
	AND create_time >= 1534953600
	AND create_time < 1535040000
LIMIT 1

加索引前,

EXPLAIN 结果 rows 为:549178

> 时间: 17.719s

加索引后:`mission_id`, `user_id`, `create_time`

EXPLAIN 结果 rows 为:1

> 时间: 0.025s



待优化的 SQL:(mag_score_mission_user 表有约 28 万条数据)

SELECT *
FROM `mag_score_mission_user`
WHERE `user_id` = 431779
	AND `mission_id` = 5
	AND `create_time` >= 1534953600
ORDER BY complete_count DESC
LIMIT 1

不加索引

1SIMPLEmag_score_mission_userALL282436Using where; Using filesort

> 时间: 7.325s


`user_id`, `mission_id`

1SIMPLEmag_score_mission_userrefix_us_miix_us_mi10const,const7Using where; Using filesort

时间: 0.014s


`user_id`, `mission_id`, `create_time`

1SIMPLEmag_score_mission_userrangeix_us_miix_us_mi151Using index condition; Using filesort

时间: 0.023s


`user_id`, `mission_id`, `complete_count`

1SIMPLEmag_score_mission_userrefix_us_miix_us_mi10const,const7Using where

> 时间: 0.014s


`user_id`, `mission_id`, `complete_count`, `create_time`

1SIMPLEmag_score_mission_userrefix_us_miix_us_mi10const,const7Using where

> 时间: 0.028s


`user_id`, `mission_id`, `create_time`, `complete_count`

1SIMPLEmag_score_mission_userrangeix_us_miix_us_mi151Using index condition; Using filesort

> 时间: 0.025s


其它就不一一举例了,根据 SHOW FULL PROCESSLIST 的慢查询自行加索引就行了。


xoyozo 7 年前
4,472

一: 执行sql语句,返回受影响的行数

在mysql里面,如果没有影响,那么返回行数为  -1 ,sqlserver 里面  还没有测试过

 (var ctx =  MyDbContext())
{
    ctx.Database.ExecuteSqlCommand("");
}


二 : Database.SqlQuery<T>   EF5执行sql查询语句 Database.SqlQuery 带返回值

这个准确的说是  IEnumerable<T> SqlQuery<T>(string sql, params object[] parameters)  ,注意返回值是 IEnumerable

这个是执行sql语句,返回你想要的类型的列表

dbMain.Database.SqlQuery<int>("select max(UserId) from tb_user_account").First();


或者假如你自己有个类别

  PersonView
{      PersonID { ; ; }      Name { ; ; }
}


那么就可以直接返回这个 PersonView类

 (var ctx =  MyDbContext())
{
    var peopleViews = ctx.SqlQuery<PersonView>("").ToList();
}

直接返回你想要的数据. 例如这里是 List<PersonView> 列表


转自 梨花驿路 7 年前
4,928

本文未完成,部分测试方法、条件或结果可能有误,请谨慎参考! :)

本文基于 MySQL 的 InnoDB BTREE 方法的索引进行测试。

以一张包含 2000 万条记录的表做实验:

CREATE TABLE `dt_read`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `time` datetime(0) NOT NULL,
  `a_id` int(11) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
);

这张表是用于记录文章点击量的,

`id` 为主键,int(11) 自增;

`time` 为非空 datetime,表示文章打开时间,测试数据是从 2017-03-11 至 2018-04-28;

`a_id` 为非空 int(11),表示文章 ID,在此表中不唯一,测试数据是从 1 至 260218。


体验“全表扫描”


首先来体验一下什么是全表扫描,执行下面语句:

SELECT * FROM `dt_read` WHERE `time` < '2020-1-1' LIMIT 10

> 时间: 0.012s


SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' LIMIT 10

> 时间: 7.317s


表中数据是按主键从小到大排列的,当查询条件为 `time` < '2020-1-1' 时,能很快地从表的前端找到 10 条满足条件的数据,所以不再继续判断后面的记录,立刻返回结果,耗时 0.012 秒;但当条件改为 `time` < '2000-1-1' 时,同样逐条判断,直到最后一条也没有找到,这种情况就是所谓的“全表扫描”,耗时 7 秒。


索引对 ORDER BY 的 ASC 和 DESC 的影响


我们给 `time` 建一个索引,同样执行刚才需要全表扫描的语句:

SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' LIMIT 10

> 时间: 0.012s


创建 `time` 的索引后,相当于生成了一张按 `time` 字段排列的新表,这时 MySQL 就能够很快地定位并找到符合条件的记录,避免了全表扫描。


试试按 `time` 倒序排:

SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' ORDER BY `time` DESC LIMIT 10

> 时间: 0.013s


结论:索引对 ORDER BY 的顺序(ASC)和倒序(DESC)都是有效的。


索引字段的次序对 WHERE 和 ORDER BY 的影响


删除所有索引,创建一个新的索引,字段依次为 `time`, `a_id`。

分别执行以下查询:


SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' AND `a_id` < 0 LIMIT 10

> 时间: 0.013s


SELECT * FROM `dt_read` WHERE `a_id` < 0 AND `time` < '2000-1-1' LIMIT 10

> 时间: 0.013s


结论:MySQL 会自动优化 WHERE 条件的次序来匹配最合适的索引。

但在 ORDER BY 中却不是这么回事了:


SELECT * FROM `dt_read` ORDER BY `time`, `a_id` LIMIT 10

> 时间: 0.013s


SELECT * FROM `dt_read` ORDER BY `a_id`, `time` LIMIT 10

> 时间: 14.066s


原因也很好理解,对两个字段进行排序,先后次序肯定会影响结果集,因此只能以 SQL 语句指定的字段次序来 ORDER BY,这样,按索引的字段次序进行 ORDER BY 查询无疑是更快的。


索引中的字段必须依次使用


保持上例创建的索引不变,即 `time`, `a_id`。


SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' AND `a_id` < 0 LIMIT 10

> 时间: 0.013s


SELECT * FROM `dt_read` WHERE `a_id` < 0 LIMIT 10

> 时间: 6.438s


上句合理利用了索引的字段,而下句跳过了 `time`,直接 WHERE 了 `a_id`,这是不受该索引支持的。

我们可以想象一下这张由索引生成的虚拟表,其实就是一张普通的平面二维表格,按索引指定的字段次序进行了排序,所以全表中仅仅是索引指定的第一个字段是按大小排列的,第二个字段是在第一个字段值相同的区域内按大小排列,后同。所以,跳过索引指定的第一个字段直接对第二个字段进行检索,是无法应用该索引的。这个结论也同样也体现在 ORDER BY 语句中:


SELECT * FROM `dt_read` ORDER BY `time`, `a_id` LIMIT 10

> 时间: 0.013s


SELECT * FROM `dt_read` ORDER BY `a_id` LIMIT 10

> 时间: 29.566s


WHERE 和 ORDER BY 混合


保持上例创建的索引不变,即 `time`, `a_id`。


先来执行这两句:


SELECT * FROM `dt_read` ORDER BY `a_id` LIMIT 10

> 时间: 12.29s


SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' ORDER BY `a_id` LIMIT 10

> 时间: 0.013s


仅仅 WHERE 了一个 `time`,对 ORDER BY `a_id` 的效率却有质的提升,是因为 WHERE 中的 `time` 和 ORDER BY 中的 `a_id` 一起找到了索引吗?答案是否定的。

我们把时间改大,让它能马上找到符合条件的数据:


SELECT * FROM `dt_read` WHERE `time` < '2020-1-1' ORDER BY `a_id` LIMIT 10

> 时间: 22.34s


为什么这个语句就不走索引了呢?

其实,一个简单的 SELECT 查询语句,首先执行 WHERE,然后 ORDER BY,最后是 LIMIT。每一步都独自去找了索引,而非 WHERE 和 ORDER BY 混在一起去找索引。必须保证每一步是快的,最终才是快的。

当 `time` < '2000-1-1' 时,WHERE 用到了索引,所以很快,ORDER BY 却没有用到索引,但为什么也很快呢?因为 WHERE 的结果集非常小(示例中为 0 条)。

当 `time` < '2020-1-1' 时,WHERE 也用到了索引,但其结果集非常大(示例中为所有记录),再 ORDER BY `a_id` 就非常慢了,因为我们没有创建以 `a_id` 开头的索引。


现在把索引改成只有 `time` 一个字段。


SELECT * FROM `dt_read` WHERE `time` < '2020-1-1' ORDER BY `a_id` LIMIT 10

> 时间: 6.033s


因为索引里有 `


SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' ORDER BY `a_id` LIMIT 10

> 时间: 0.013s


SELECT * FROM `dt_read` WHERE `a_id` < 0 ORDER BY `time` LIMIT 10

> 时间: 6.033s


第二句先 WHERE `a_id`,后 ORDER BY `time` 是不能匹配所建的索引的。


索引中的字段越多越好


分别在创建索引(`time`)和索引(`time`, `a_id`)的情况下执行下面语句:

本例使用 ORDER BY 而不是 WHERE 来测试是因为,在 WHERE 的多个条件下,如果符合前一条件的筛选结果集过小会导致判断第二条件时数据量不足,无法判断索引是否起作用。


SELECT * FROM `dt_read` ORDER BY `time` LIMIT 10


仅创建索引(`time`)的情况下:

> 时间: 0.013s


仅创建索引(`time`, `a_id`)的情况下:

> 时间: 0.013s


SELECT * FROM `dt_read` ORDER BY `time`, `a_id` LIMIT 10


仅创建索引(`time`)的情况下:

> 时间: 15.015s


仅创建索引(`time`, `a_id`)的情况下:

> 时间: 0.014s


可以看到,在索引字段依次使用的前提下,索引字段数不少于查询字段数才能避免全表扫描。

虽然索引中的字段越多越好,但必须依次使用,否则也是无效索引。


索引对 INSERT / UPDATE / DELETE 的效率影响


分别在创建索引(`time`)和索引(`time`, `a_id`)的情况下执行下面语句:


INSERT INTO `dt_read` (`time`, `a_id`) VALUES ('2018-4-28', 260218)


不建索引的情况下:

> 时间: 0.01s


仅创建索引(`time`)的情况下:

> 时间: 0.01s


同时创建索引(`time`)和索引(`time`, `a_id`)的情况下:

> 时间: 0.01s


UPDATE `dt_read` SET `time` = '2018-4-28' WHERE `id` = 20000000(注:存在该 id 值的记录)


不建索引的情况下:

> 时间: 0.01s


仅创建索引(`time`)的情况下:

> 时间: 0.01s


同时创建索引(`time`)和索引(`time`, `a_id`)的情况下:

> 时间: 0.01s


虽然在 INSERT / UPDATE / DELETE 时数据库会更新索引,但从实测数据来看,索引对其效率的影响可忽略不计。


一些误区


“in 语法效率很低”?

in 语法也是应用索引的,网传 in 会比一个一个 WHERE OR 要慢得多的说法是不靠谱的。in 主键和 in 索引同理。


另外:

对于字符串类型,LIKE '%abc%' 是不能应用索引的,但 LIKE 'abc%' 可以。更多关于字符串类型的索引,请查阅全文索引(FULLTEXT)。

索引的字段是可以指定长度的,类似字符串索引指定前面若干唯一字符就可以优化效率。


本文系个人实践总结,欢迎批评指正!


xoyozo 7 年前
4,443

EF 提供一个查询 SQL 日志的属性:

DbContext.Database.Log

该属性是一个委托。

最简单的用法是直接输出到控制台:

DbContext.Database.Log = Console.WriteLine;

WebFrom 中可以输出到页面:

DbContext.Database.Log = Response.Write;

该委托可以带一个参数,利用它可以输出简单格式化的日志信息:

DbContext.Database.Log = (sql) =>
{
    Console.WriteLine("查询开始");
    Console.WriteLine(sql);
    Console.WriteLine("查询结束");
};

上面是直接输出到控制台或页面,当然也可以保存到变量:

string s = "";
DbContext.Database.Log = (sql) =>
{
    s += sql;
};

当然还有更强大更广泛的使用方式,有兴趣可以参阅 Jeffcky 的文章

xoyozo 8 年前
8,139

首先要有个工行U盾,一台手机。

苹果用户在 App Store 中搜索 中国工商银行 和 工商银行通用U盾

安卓用户从 m.icbc.com.cn 网站下载安装客户端。


image.png  image.png


以 iPhone 为例:


打开工行U盾 App,选择U盾厂商(我的是“天地融”,无法确定的可以在此查询

把U盾插入手机的耳机孔,状态显示“已连接”

此时点击“查看证书”提示未安装证书


打开中国工商银行 App,进入:我的 - 安全中心 - 支付管理 - 安全介质管理 - U盾证书下载

依照提示安装证书

现在可以愉快地大额转账啦!


xoyozo 8 年前
17,354