博客 (81)

〓 系统

功能命令--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 6 年前
6,104

xhEditorKindEditorCKEditor百度 UEditor

1.1.144.1.33.6.41.4.3.2
分页功能×
表格右键功能(添加删除列、合并单元格等)×
HTML5下能直接从本地拖曳至浏览器上传图片××
远程图片抓取××
Word 图片转存×××
直接粘贴剪切板中的图片(指类似屏幕截图,不指网页上图片右键复制,因为后者属于“远程图片抓取”)××
本地草稿×××

上表中的部分功能可能需要通过配置或安装插件来实现。
本文编辑时间为2012年10月7日,文中若有错误或编辑器的新版本支持了上述功能,请通过QQ940534113告诉我。
非常感谢您的支持!

xoyozo 6 年前
3,640

本文不定时更新中……


具备 RESTful 相关知识会更有利于学习 ASP.NET Web API:RESTful API 学习笔记

ASP.NET Web API 官网:https://www.asp.net/web-api


服务 URI Pattern

ActionHttp verbURI说明
Get contact listGET/api/contacts列表
Get filtered contactsGET/api/contacts?$top=2筛选列表
Get contact by IDGET/api/contacts/id获取一项
Create new contactPOST/api/contacts增加一项
Update a contactPUT/api/contacts/id修改一项
Delete a contactDELETE/api/contacts/id
删除一项


返回类型Web API 创建响应的方式
void返回空 204 (无内容)
HttpResponseMessage转换为直接 HTTP 响应消息。
IHttpActionResult调用 ExecuteAsync 来创建 HttpResponseMessage,然后将转换为 HTTP 响应消息。
其他类型将序列化的返回值写入到响应正文中;返回 200 (正常)。

HttpResponseMessage

可提供大量控制的响应消息。 例如,以下控制器操作设置的缓存控制标头。

public class ValuesController : ApiController
{
    public HttpResponseMessage Get()
    {
        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
        response.Content = new StringContent("hello", Encoding.Unicode);
        response.Headers.CacheControl = new CacheControlHeaderValue()
        {
            MaxAge = TimeSpan.FromMinutes(20)
        };
        return response;
    } 
}

IHttpActionResult

public IHttpActionResult Get (int id)
{
    Product product = _repository.Get (id);
    if (product == null)
    {
        return NotFound(); // Returns a NotFoundResult
    }
    return Ok(product);  // Returns an OkNegotiatedContentResult
}

其他的返回类型

响应状态代码为 200 (正常)。此方法的缺点是,不能直接返回错误代码,如 404。 但是,您可以触发 HttpResponseException 的错误代码


完善 Help 页

一般都是通过元数据注释(Metadata Annotations)来实现的描述的。


显示接口和属性的描述:

打开 HelpPage 区域的 App_Start 目录下的 HelpPageConfig.cs 文件,在 Register 方法的首行取消注释行:

config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));

在项目右键属性“生成”页,勾选“XML 文档文件”,并填写与上述一致的路径(App_Data/XmlDocument.xml)。


给接口加上 ResponseType 显示响应描述和示例:[ResponseType(typeof(TEntity))]


在实体模型的属性上加入 RequiredAttribute 特性可提供请求或响应中的实体的属性描述,如:[Required]


推荐使用:Swashbuckle

关于格式


在 WebApiConfig.Register() 中加入以下代码以禁止以 XML 格式输出(请按需设置):

GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

Json 序列化去掉 k__BackingField

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver { IgnoreSerializableAttribute = true };

如果属性值为 null 则不序列化该属性

config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };



xoyozo 6 年前
4,268

前言:

本文适合 6.x 环境,8.x 请结合参考:如何升级 ASP.NET 项目 MySql.Data 和 Connector/NET 至 8.0.x

使用 ASP.NET Core 的同学请移步:ASP.NET Core 使用 DBFirst 模式连接 MySQL 数据库


安装


开发环境


软件安装:


版本选择:

  • MySQL for Visual Studio 最新版

  • Connector/NET 版本必须与 MySql.Data 和 MySql.Data.Entity 版本相同,否则会出现 MySql.Data.MySqlClient.MySqlConnection 无法强制转换的错误


生产环境


软件安装:

  • MySQL Server - 数据库

  • Connector/NET - ADO.NET 托管提供程序


版本选择:

  • MySQL Server 最新版

  • Connector/NET 应与项目中使用的 MySql.Data 和 MySql.Data.Entity 版本一致。(某些项目在确保 Web.config 的 MySql.Data 版本号与 MySql.Data 和 MySql.Data.Entity 版本一致的前提下,允许服务端的 Connector/NET 小版本略低于 MySql.Data 和 MySql.Data.Entity 版本,某些项目允许安装比 MySql.Data 和 MySql.Data.Entity 版本略高的 Connector/NET 版本,为确保不出问题,严格要求版本全部一致)


升级

  • MySQL for Visual Studio:直接更新至最新版

  • MySQL Server:直接更新至最新版

  • MySql.Data 和 MySql.Data.Entity:升级至两者共有的新版本,更改 Web.config 中 MySql.Data 的版本号,并更新开发环境和生产环境的 Connector/NET 至相同版本(详细步骤见下方说明)

  • Connector/NET:视是否有相同版本的 MySql.Data 和 MySql.Data.Entity,若有,同时升级。(详细步骤见下方说明)


关于 Connector/NET 和 MySql.Data 及 MySql.Data.Entity 版本一致的说明:

某些项目在确保 Web.config 的 MySql.Data 版本号与 MySql.Data 和 MySql.Data.Entity 版本一致的前提下,允许服务端的 Connector/NET 小版本略低于 MySql.Data 和 MySql.Data.Entity 版本

某些项目允许安装比 MySql.Data 和 MySql.Data.Entity 版本略高的 Connector/NET 版本

为确保不出问题,严格要求版本全部一致。

但服务器上同时运行多个项目,一旦出现问题涉及面就很广,为了尽量减少影响,列出下面的升级步骤:

  1. 升级开发环境 Connector/NET

  2. 升级各项目的 MySql.Data 和 MySql.Data.Entity

  3. 更改 Web.config 中关于 MySql.Data 的版本号(若未自动更新,项目中搜索原版本号即可)

  4. 测试运行各项目

  5. 同时发布各项目,同时升级服务器上的 Connector/NET(升级 Connector/NET 仅需几十秒)

  6. 部分项目需要删除并重新上传 bin 目录才能生效

  7. 尽管如此,发布成功以后还是会有各种各样的问题导致无法正常打开,须要有针对性地去解决,所以升级还是要趁夜深人静的时候进行

xoyozo 6 年前
4,887

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

本文基于 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 年前
3,705

删除主题时,会变更主题表 pre_forum_thread:

displayorder = -1

moderated = 1

帖子表(或分表) pre_forum_post* 该主题的所有帖子的

invisible = -1

同时 pre_forum_threadmod 会新增一条 DEL 记录,用于显示到 Discuz! 控制面板 - 内容 - 主题回收站。


删除回帖时,会变更回帖表 pre_forum_post(或分表):

invisible = -5


屏蔽回复时,会变更回复表 pre_forum_post(或分表):

status = 1

xoyozo 7 年前
4,205

I`L8{$7ET7)3BUEREPIWIKB.png

ASP.NET MVC 项目发布到 IIS 上,出现服务器错误“403 - 禁止访问:访问被拒绝”,排除权限设置问题后,原因在于 MVC 的 URL 通常没有扩展名,IIS 并未将其交由 ASP.NET 托管处理。

经过各种找资料,各种尝试后,最终确定:项目本身没有问题,本地运行正常,发布到另一台服务器上正常。

删除服务器 IIS 上的该网站和应用程序池,重新创建网站,恢复正常。原因未知。

xoyozo 7 年前
7,954
发布选项 \ 项目类型Web 窗体网站

Web 应用程序

(Web 窗体)

Web 应用程序

(MVC)

ASP.NET Core 

Web 应用程序

在发布期间预编译

Precompile during publishing

若勾选,将 .cs 文件编译为 .dll
无论是否勾选,都将 .cs 文件编译为 .dll

允许更新预编译站点

Allow precompiled site to be updatable

若不允许,则会将 .aspx 等页面也一同编译,并以内容“这是预编译工具生成的标记文件,不应删除!”代替

未进行完整的测试和分析,总结有误请指正。

xoyozo 7 年前
5,178

函数功能:添加/修改/删除/获取 URL 中的参数(锚点敏感)

/// <summary>
/// 设置 URL 参数(设 value 为 undefined 或 null 删除该参数)
/// <param name="url">URL</param>
/// <param name="key">参数名</param>
/// <param name="value">参数值</param>
/// </summary>
function fn_set_url_param(url, key, value) {
    // 第一步:分离锚点
    var anchor = "";
    var anchor_index = url.indexOf("#");

    if (anchor_index >= 0) {
        anchor = url.substr(anchor_index);
        url = url.substr(0, anchor_index);
    }

    // 第二步:删除参数
    key = encodeURIComponent(key);
    var patt;

    // &key=value
    patt = new RegExp("\\&" + key + "=[^&]*", "gi");
    url = url.replace(patt, "");

    // ?key=value&okey=value  -> ?okey=value
    patt = new RegExp("\\?" + key + "=[^&]*\\&", "gi");
    url = url.replace(patt, "?");

    // ?key=value
    patt = new RegExp("\\?" + key + "=[^&]*$", "gi");
    url = url.replace(patt, "");

    // 第三步:追加参数
    if (value != undefined && value != null) {
        value = encodeURIComponent(value);
        url += (url.indexOf("?") >= 0 ? "&" : "?") + key + "=" + value;
    }

    // 第四步:连接锚点
    url += anchor;

    return url;
}

/// <summary>
/// 获取 URL 参数(无此参数返回 null,多次匹配使用“,”连接)
/// <param name="url">URL</param>
/// <param name="key">参数名</param>
/// </summary>
function fn_get_url_param(url, key) {
    key = encodeURIComponent(key);
    var patt = new RegExp("[?&]" + key + "=([^&#]*)", "gi");

    var values = [];

    while ((result = patt.exec(url)) != null) {
        values.push(decodeURIComponent(result[1]));
    }

    if (values.length > 0) {
        return values.join(",");
    } else {
        return null;
    }
}


调用示例:

var url = window.location.href;

// 设置参数
url = fn_set_url_param(url, 'a', 123);

// 获取参数
console.log(fn_get_url_param, url, 'a');


压缩版:

function fn_set_url_param(b,c,e){var a="";var f=b.indexOf("#");if(f>=0){a=b.substr(f);b=b.substr(0,f)}c=encodeURIComponent(c);var d;d=new RegExp("\\&"+c+"=[^&]*","gi");b=b.replace(d,"");d=new RegExp("\\?"+c+"=[^&]*\\&","gi");b=b.replace(d,"?");d=new RegExp("\\?"+c+"=[^&]*$","gi");b=b.replace(d,"");if(e!=undefined&&e!=null){e=encodeURIComponent(e);b+=(b.indexOf("?")>=0?"&":"?")+c+"="+e}b+=a;return b}
function fn_get_url_param(b,c){c=encodeURIComponent(c);var d=new RegExp("[?&]"+c+"=([^&#]*)","gi");var a=[];while((result=d.exec(b))!=null){a.push(decodeURIComponent(result[1]))}if(a.length>0){return a.join(",")}else{return null}};


xoyozo 7 年前
3,431

优点缺点
大白菜

可还原 U 盘空间

支持 UEFI

众多山寨产品,分不清哪个是正宗老牌,说不定还是新秀更优秀

Window 10 自带防病毒软件 Window Defender 提示发现威胁

一键制作的大白菜U盘,将 iso 拷入U盘后安装的纯净系统会被捆绑安装垃圾软件

老毛桃

可还原 U 盘空间

支持 UEFI

PE 还不错

“ISO 模式”没什么问题,但“一键制作”的是 FAT32 格式,不支持将大于 4GB 的 ISO 镜像拷贝到 U 盘

“模拟启动”可启动老毛桃界面,但直接写入硬盘映像的 U 盘无法模拟启动

卸载时,Window 10 自带防病毒软件 Window Defender 提示发现特洛伊木马

软碟通 UltraISO

中规中矩

写入硬盘不会自动还原 U 盘空间

网上找序列号激活

Ventoy

推荐!

开源

可同时拷入多个系统镜像文件,并支持启动时选择

可支持格式化为多种文件格式

一键制作,可升级

暂无

软碟通制作 Windows 系统安装盘过程:

  1. 下载微软官方提供的 iso 系统镜像文件

  2. 如果 U 盘容量缩水,或根本无法正常使用 U 盘,使用老毛桃还原 U 盘空间

  3. 打开 UltraISO,打开要写入 U 盘的 iso 文件

  4. 在菜单上选择:启动 - 写入盘映像...

  5. 选择硬盘驱动器,格式化,写入(注意:点击“写入”是按 FAT32 重新格式化的,若要制作 NTFS 文件系统的 U 盘,请先按 NTFS 格式化,然后在此界面上点击“便捷启动”-“便捷写入”)

  6. 如果 U 盘足够大,可以在 U 盘里多放几个系统镜像,双击打开另一个 iso,将所有文件和文件夹复制到 U 盘上新建的目录中。这样下次需要安装什么系统时,只要把对应的系统的文件放到 U 盘根目录,其它系统移到二级目录中即可。当然还可以往里面存放一些常用软件。

另外最好常备一个带有 PE 系统的启动盘,在旧电脑上安装旧系统时经常会用到。

如果在分区那步无法删除或创建分区(提示动态卷什么的),在确认放弃磁盘中的文件的前提下,可以使用 Shift + F10 调出命令行,键入 diskpart,列出磁盘(list disk),选择磁盘(select disk 0),清除(clean),注意 U 盘启动盘也会在列表中,勿删!

xoyozo 7 年前
8,748