first commit

This commit is contained in:
iProbe 2022-10-18 16:59:37 +08:00
commit ba848e218d
1001 changed files with 152333 additions and 0 deletions

View file

@ -0,0 +1,210 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="tool" content="leanote-desktop-app">
<title>MongoDB数据表基本操作</title>
<style>
*{font-family:"lucida grande","lucida sans unicode",lucida,helvetica,"Hiragino Sans GB","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;}
body {
margin: 0;
}
/*公用文字样式*/
h1{font-size:30px}h2{font-size:24px}h3{font-size:18px}h4{font-size:14px}
.note-container{
width:850px;
margin:auto;
padding: 10px 20px;
box-shadow: 1px 1px 10px #eee;
}
#title {
margin: 0;
}
table {
margin-bottom: 16px;
border-collapse: collapse;
}
table th, table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
table th {
font-weight: bold;
}
table tr {
background-color: none;
border-top: 1px solid #ccc;
}
table tr:nth-child(2n) {
background-color: rgb(247, 247, 249);
}
.mce-item-table, .mce-item-table td, .mce-item-table th, .mce-item-table caption {
border: 1px solid #ddd;
border-collapse: collapse;
padding: 6px 13px;
}
blockquote {
border-left-width:10px;
background-color:rgba(128,128,128,0.05);
border-top-right-radius:5px;
border-bottom-right-radius:5px;
padding:15px 20px;
border-left:5px solid rgba(128,128,128,0.075);
}
blockquote p {
margin-bottom:1.1em;
font-size:1em;
line-height:1.45
}
blockquote ul:last-child,blockquote ol:last-child {
margin-bottom:0
}
pre {
padding: 18px;
background-color: #f7f7f9;
border: 1px solid #e1e1e8;
border-radius: 3px;
display: block;
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
white-space: nowrap;
background-color: #f9f2f4;
border-radius: 4px;
}
.footnote {
vertical-align: top;
position: relative;
top: -0.5em;
font-size: .8em;
}
hr {
margin:2em 0
}
img {
max-width:100%
}
pre {
word-break:break-word
}
p,pre,pre.prettyprint,blockquote {
margin:0 0 1.1em
}
hr {
margin:2em 0
}
img {
max-width:100%
}
.sequence-diagram,.flow-chart {
text-align:center;
margin-bottom:1.1em
}
.sequence-diagram text,.flow-chart text {
font-size:15px !important;
font-family:"Source Sans Pro",sans-serif !important
}
.sequence-diagram [fill="#ffffff"],.flow-chart [fill="#ffffff"] {
fill:#f6f6f6
}
.sequence-diagram [stroke="#000000"],.flow-chart [stroke="#000000"] {
stroke:#3f3f3f
}
.sequence-diagram text[stroke="#000000"],.flow-chart text[stroke="#000000"] {
stroke:none
}
.sequence-diagram [fill="#000"],.flow-chart [fill="#000"],.sequence-diagram [fill="#000000"],.flow-chart [fill="#000000"],.sequence-diagram [fill="black"],.flow-chart [fill="black"] {
fill:#3f3f3f
}
ul,ol {
margin-bottom:1.1em
}
ul ul,ol ul,ul ol,ol ol {
margin-bottom:1.1em
}
kbd {
padding:.1em .6em;
border:1px solid rgba(63,63,63,0.25);
-webkit-box-shadow:0 1px 0 rgba(63,63,63,0.25);
box-shadow:0 1px 0 rgba(63,63,63,0.25);
font-size:.7em;
font-family:sans-serif;
background-color:#fff;
color:#333;
border-radius:3px;
display:inline-block;
margin:0 .1em;
white-space:nowrap
}
.toc ul {
list-style-type:none;
margin-bottom:15px
}
</style>
<!-- 该css供自定义样式 -->
<link href="../leanote-html.css" rel="stylesheet">
</head>
<body>
<div class="note-container">
<h1 class="title" id="leanote-title">MongoDB数据表基本操作</h1>
<div class="content-html" id="leanote-content"><p>查看全部数据表</p><pre id="leanote_ace_1479781232163_0" class="brush:sh ace-tomorrow">&gt;&nbsp;use&nbsp;ChatRoom
switched&nbsp;to&nbsp;db&nbsp;ChatRoom
&gt;&nbsp;show&nbsp;collections
Account
Chat
system.indexes
system.users</pre><p>创建数据表</p><pre id="leanote_ace_1479781278873_0" class="brush:sh ace-tomorrow">&gt;&nbsp;db.createCollection("Account")
{"ok":1}</pre><pre id="leanote_ace_1479781293825_0" class="brush:sh ace-tomorrow">&gt;&nbsp;db.createCollection("Test",{capped:true,&nbsp;size:10000})&nbsp;{&nbsp;"ok"&nbsp;:&nbsp;1&nbsp;}
{"ok":1}</pre><p>-- 说明</p><p>capped:true表示该集合的结构不能被修改</p><p>size:在建表之初就指定一定的空间大小接下来的插入操作会不断地按顺序APPEND数据在这个预分配好空间的文件中如果已经超出空间大小则回到文件头覆盖原来的数据继续插入。这种结构保证了插入和查询的高效性它不允许删除单个记录更新的也有限制不能超过原有记录的大小。这种表效率很高它适用于一些暂时保存数据的场合比如网站中登录用户的session信息又比如一些程序的监控日志都是属于过了一定的时间就可以被覆盖的数据。</p><p>&nbsp;<br></p><p>修改数据表名</p><pre id="leanote_ace_1479781320849_0" class="brush:sh ace-tomorrow">&gt;&nbsp;db.Account.renameCollection("Account1")
{&nbsp;"ok"&nbsp;:&nbsp;1&nbsp;}</pre><p>&nbsp;<br></p><p>数据表帮助主题help</p><pre id="leanote_ace_1479781866930_0" class="brush:sh ace-tomorrow">&gt;&nbsp;db.Account.help()
DBCollection&nbsp;help
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.find().help()&nbsp;-&nbsp;show&nbsp;DBCursor&nbsp;help
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.count()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.dataSize()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.distinct(&nbsp;key&nbsp;)&nbsp;-&nbsp;eg.&nbsp;db.Account.distinct(&nbsp;'x'&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.drop()&nbsp;drop&nbsp;the&nbsp;collection
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.dropIndex(name)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.dropIndexes()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.ensureIndex(keypattern[,options])&nbsp;-&nbsp;options&nbsp;is&nbsp;an&nbsp;object&nbsp;with&nbsp;these&nbsp;possible&nbsp;fields:&nbsp;name,&nbsp;unique,&nbsp;dropDups
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.reIndex()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.find([query],[fields])&nbsp;-&nbsp;query&nbsp;is&nbsp;an&nbsp;optional&nbsp;query&nbsp;filter.&nbsp;fields&nbsp;is&nbsp;optional&nbsp;set&nbsp;of&nbsp;fields&nbsp;to&nbsp;retur.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.g.&nbsp;db.Account.find(&nbsp;{x:77}&nbsp;,&nbsp;{name:1,&nbsp;x:1}&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.find(...).count()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.find(...).limit(n)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.find(...).skip(n)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.find(...).sort(...)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.findOne([query])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.findAndModify(&nbsp;{&nbsp;update&nbsp;:&nbsp;...&nbsp;,&nbsp;remove&nbsp;:&nbsp;bool&nbsp;[,&nbsp;query:&nbsp;{},&nbsp;sort:&nbsp;{},&nbsp;'new':&nbsp;false]&nbsp;}&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.getDB()&nbsp;get&nbsp;DB&nbsp;object&nbsp;associated&nbsp;with&nbsp;collection
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.getIndexes()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.group(&nbsp;{&nbsp;key&nbsp;:&nbsp;...,&nbsp;initial:&nbsp;...,&nbsp;reduce&nbsp;:&nbsp;...[,&nbsp;cond:&nbsp;...]&nbsp;}&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.mapReduce(&nbsp;mapFunction&nbsp;,&nbsp;reduceFunction&nbsp;,&nbsp;&lt;optional&nbsp;params&gt;&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.remove(query)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.renameCollection(&nbsp;newName&nbsp;,&nbsp;&lt;dropTarget&gt;&nbsp;)&nbsp;renames&nbsp;the&nbsp;collection.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.runCommand(&nbsp;name&nbsp;,&nbsp;&lt;options&gt;&nbsp;)&nbsp;runs&nbsp;a&nbsp;db&nbsp;command&nbsp;with&nbsp;the&nbsp;given&nbsp;name&nbsp;where&nbsp;the&nbsp;first&nbsp;param&nbsp;is&nbsp;the&nbsp;collection&nbsp;name
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.save(obj)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.stats()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.storageSize()&nbsp;-&nbsp;includes&nbsp;free&nbsp;space&nbsp;allocated&nbsp;to&nbsp;this&nbsp;collection
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.totalIndexSize()&nbsp;-&nbsp;size&nbsp;in&nbsp;bytes&nbsp;of&nbsp;all&nbsp;the&nbsp;indexes
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.totalSize()&nbsp;-&nbsp;storage&nbsp;allocated&nbsp;for&nbsp;all&nbsp;data&nbsp;and&nbsp;indexes
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.update(query,&nbsp;object[,&nbsp;upsert_bool,&nbsp;multi_bool])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.validate()&nbsp;-&nbsp;SLOW
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.Account.getShardVersion()&nbsp;-&nbsp;only&nbsp;for&nbsp;use&nbsp;with&nbsp;sharding&nbsp;</pre><p>&nbsp;<br></p><p>查看全部表记录</p><pre id="leanote_ace_1479782012602_0" class="brush:sh ace-tomorrow">&gt;&nbsp;db.Account.find()
{&nbsp;"_id"&nbsp;:&nbsp;ObjectId("4df08553188e444d001a763a"),&nbsp;"AccountID"&nbsp;:&nbsp;1,&nbsp;"UserName"&nbsp;:&nbsp;"libing",&nbsp;"Password"&nbsp;:&nbsp;"1",&nbsp;"Age"&nbsp;:&nbsp;26,&nbsp;"Email"&nbsp;:&nbsp;"libing@126.com",&nbsp;"RegisterDate"&nbsp;:&nbsp;"2011-06-09&nbsp;16:31:25"&nbsp;}
{&nbsp;"_id"&nbsp;:&nbsp;ObjectId("4df08586188e444d001a763b"),&nbsp;"AccountID"&nbsp;:&nbsp;2,&nbsp;"UserName"&nbsp;:&nbsp;"lb",&nbsp;"Password"&nbsp;:&nbsp;"1",&nbsp;"Age"&nbsp;:&nbsp;25,&nbsp;"Email"&nbsp;:&nbsp;"libing@163.com",&nbsp;"RegisterDate"&nbsp;:&nbsp;"2011-06-09&nbsp;16:36:95"&nbsp;}</pre><p>&nbsp;<br></p></div>
</div>
<!-- 该js供其它处理 -->
<script src="../leanote-html.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,8 @@
导出
```
mongodump -h xxx -d dbname -u dbuser -o dir
```
导入
```
mongorestore -h xxxxxx -d dbname -u dbuser dbfile
```

View file

@ -0,0 +1,5 @@
B树的非叶子节点也存储数据而每层节点有16k大小(mysql),所以存储的数据会比较少
B+树的非叶子节点上不存储数据叶子节点包含所有索引字段每层节点就会多存很多索引8b索引+6b下级分叉的地址
查询innodb的分页大小
show gloobal status like 'innodb_page_size';

View file

@ -0,0 +1,9 @@
mha在所有mysql节点上安装mha node还需要安装mha managermha manager定时监控主节点的状态
从宕机崩溃的master保存二进制日志事件binlog events
识别含有最新更新的slave
应用差异的中继日志relay log到其他slave
应用从master保存的二进制日志事件binlog events
提升一个slave为新master
使用其他的slave连接新的master进行复制。

7
数据库/mysql/MVCC.md Normal file
View file

@ -0,0 +1,7 @@
在Mysql的InnoDB引擎中就是指在已提交读(READ COMMITTD)和可重复读(REPEATABLE READ)这两种隔离级别下的事务对于SELECT操作会访问版本链中的记录的过程。即对数据做了快照。
快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本)不用加锁共享读锁s锁也不加所以不会阻塞其他事务的写
当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录
InnoDB的MVCC是通过在每行纪录后面保存两个隐藏的列来实现的。这两个列一个保存了行的创建时间一个保存了行的过期时间或删除时间当然存储的并不是实际的时间值而是系统版本号。每开始一个新的事务系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号用来和查询到的每行纪录的版本号进行比较

View file

@ -0,0 +1,866 @@
MySQL 5.6引入的GTID(Global Transaction IDs)使得其复制功能的配置、监控及管理变得更加易于实现,且更加健壮。
要在MySQL 5.6中使用复制功能,其服务配置段[mysqld]中至少应该定义如下选项:
binlog-format二进制日志的格式有row、statement和mixed几种类型
需要注意的是当设置隔离级别为READ-COMMITED必须设置二进制日志格式为ROW现在MySQL官方认为STATEMENT这个已经不再适合继续使用但mixed类型在默认的事务隔离级别下可能会导致主从数据不一致
log-slave-updates、gtid-mode、enforce-gtid-consistency、report-port和report-host用于启动GTID及满足附属的其它需求
master-info-repository和relay-log-info-repository启用此两项可用于实现在崩溃时保证二进制及从服务器安全的功能
sync-master-info启用之可确保无信息丢失
slave-paralles-workers设定从服务器的SQL线程数0表示关闭多线程复制功能
binlog-checksum、master-verify-checksum和slave-sql-verify-checksum启用复制有关的所有校验功能
binlog-rows-query-log-events启用之可用于在二进制日志记录事件相关的信息可降低故障排除的复杂度
log-bin启用二进制日志这是保证复制功能的基本前提
server-id同一个复制拓扑中的所有服务器的id号必须惟一
report-host
The host name or IP address of the slave to be reported to the master during slave registration. This value appears in the output of SHOW SLAVE HOSTS on the master server.
report-port:
The TCP/IP port number for connecting to the slave, to be reported to the master during slave registration.
master-info-repository:
The setting of this variable determines whether the slave logs master status and connection information to a FILE (master.info), or to a TABLE (mysql.slave_master_info)
relay-log-info-repository
This option causes the server to log its relay log info to a file or a table.
log_slave_updates
Whether updates received by a slave server from a master server should be logged to the slave's own binary log. Binary logging must be enabled on the slave for this variable to have any effect.
enforce_gtid_consistency
### 一、简单主从模式配置步骤
#### 1、配置主从节点的服务配置文件
1.1、配置master节点
```
[mysqld]
binlog-format=ROW
log-bin=master-bin
log-slave-updates=true
gtid-mode=on
enforce-gtid-consistency=true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info=1
slave-parallel-workers=2
binlog-checksum=CRC32
master-verify-checksum=1
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1
server-id=1
report-port=3306
port=3306
datadir=/mydata/data
socket=/tmp/mysql.sock
report-host=master.magedu.com
```
1.2、配置slave节点
```
[mysqld]
binlog-format=ROW
log-slave-updates=true
gtid-mode=on
enforce-gtid-consistency=true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info=1
slave-parallel-workers=2
binlog-checksum=CRC32
master-verify-checksum=1
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1
server-id=11
report-port=3306
port=3306
log-bin=mysql-bin.log
datadir=/mydata/data
socket=/tmp/mysql.sock
report-host=slave.magedu.com
```
#### 2、创建复制用户
```
mysql> GRANT REPLICATION SLAVE ON *.* TO repluser@172.16.100.7 IDENTIFIED BY 'replpass';
```
说明172.16.100.7是从节点服务器;如果想一次性授权更多的节点,可以自行根据需要修改;
#### 3、为备节点提供初始数据集
锁定主表备份主节点上的数据将其还原至从节点如果没有启用GTID在备份时需要在master上使用show master status命令查看二进制日志文件名称及事件位置以便后面启动slave节点时使用。
#### 4、启动从节点的复制线程
如果启用了GTID功能则使用如下命令
```
mysql> CHANGE MASTER TO MASTER_HOST='master.magedu.com', MASTER_USER='repluser', MASTER_PASSWORD='replpass', MASTER_AUTO_POSITION=1;
```
没启用GTID需要使用如下命令
```
slave> CHANGE MASTER TO MASTER_HOST='172.16.100.6',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='replpass',
-> MASTER_LOG_FILE='master-bin.000003',
-> MASTER_LOG_POS=1174;
```
### 二、半同步复制
#### 1、分别在主从节点上安装相关的插件
```
master> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
slave> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
```
#### 2、启用半同步复制
在master上的配置文件中添加
```
rpl_semi_sync_master_enabled=ON
```
在至少一个slave节点的配置文件中添加
```
rpl_semi_sync_slave_enabled=ON
```
而后重新启动mysql服务即可生效。
或者也可以mysql服务上动态启动其相关功能
```
master> SET GLOBAL rpl_semi_sync_master_enabled = ON;
slave> SET GLOBAL rpl_semi_sync_slave_enabled = ON;
slave> STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;
```
#### 3、确认半同步功能已经启用
```
master> CREATE DATABASE magedudb;
master> SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
slave> SHOW DATABASES;
```
### 三、MySQL Proxy
#### 1、源码安装时MySQL proxy的依赖关系
```
libevent 1.x or higher (1.3b or later is preferred).
lua 5.1.x or higher.
glib2 2.6.0 or higher.
pkg-config.
libtool 1.5 or higher.
MySQL 5.0.x or higher developer files.
```
#### 2、安装
```
# tar zxf mysql-proxy-0.8.2.tar.gz
# cd mysql-proxy-0.8.2
# ./configure
# make
# make check
```
如果管理员有密码,上面的步骤则需要使用如下格式进行:
```
# MYSQL_PASSWORD=root_pwd make check
# make install
```
默认情况下, mysql-proxy安装在/usr/local/sbin/mysql-proxy而Lua示例脚本安装在/usr/local/share目录中。
3、配置指令
mysql proxy的各配置参数请参见官方文档http://dev.mysql.com/doc/refman/5.6/en/mysql-proxy-configuration.html
使用rpm包在rhel6上安装mysql-proxy-0.8.2,其会提供配置文件及服务脚本,但没有提供读写分享的脚本。
/etc/sysconfig/mysql-proxy文件用于定义mysql-proxy的启动参数。
ADMIN_USER the user for the proxy's admin interface. You can leave the default admin user.
ADMIN_PASSWORD the password for the admin user in clear text. Change the default password for better security.
ADMIN_LUA_SCRIPT the admin script in the Lua programming language. Without this script the admin interface cannot work. You can leave the default value.
PROXY_USER the system user under which the proxy will work. By default it is mysql-proxy, and it's safe to leave it as is.
PROXY_OPTIONS proxy options such as logging level, plugins, and Lua scripts to be loaded.
其中PROXY_OPTIONS是最常用的一个选项用于定义mysql-proxy工作时的重要参数例如
PROXY_OPTIONS="--daemon --log-level=info --log-use-syslog --plugins=proxy --plugins=admin --proxy-backend-addresses=192.168.1.102:3306 --proxy-read-only-backend-addresses=192.168.1.105:3306 --proxy-lua-script=/usr/lib/mysql-proxy/lua/proxy/rw-splitting.lua"
### 四、安装配置mysql-proxy:
#### 4.1 下载所需要的版本这里的系统平台为rhel6.4 32位系统因此就以mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit.tar.gz为例。
```
# tar xf mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit.tar.gz -C /usr/local
# cd /usr/local
# ln -sv mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit mysql-proxy
```
添加代理用户
```
# useradd mysql-proxy
```
4.2 为mysql-proxy提供SysV服务脚本内容如下所示
```
#!/bin/bash
#
# mysql-proxy This script starts and stops the mysql-proxy daemon
#
# chkconfig: - 78 30
# processname: mysql-proxy
# description: mysql-proxy is a proxy daemon for mysql
# Source function library.
. /etc/rc.d/init.d/functions
prog="/usr/local/mysql-proxy/bin/mysql-proxy"
# Source networking configuration.
if [ -f /etc/sysconfig/network ]; then
. /etc/sysconfig/network
fi
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
# Set default mysql-proxy configuration.
ADMIN_USER="admin"
ADMIN_PASSWD="admin"
ADMIN_LUA_SCRIPT="/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
PROXY_OPTIONS="--daemon"
PROXY_PID=/var/run/mysql-proxy.pid
PROXY_USER="mysql-proxy"
# Source mysql-proxy configuration.
if [ -f /etc/sysconfig/mysql-proxy ]; then
. /etc/sysconfig/mysql-proxy
fi
RETVAL=0
start() {
echo -n $"Starting $prog: "
daemon $prog $PROXY_OPTIONS --pid-file=$PROXY_PID --proxy-address="$PROXY_ADDRESS" --user=$PROXY_USER --admin-username="$ADMIN_USER" --admin-lua-script="$ADMIN_LUA_SCRIPT" --admin-password="$ADMIN_PASSWORD"
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
touch /var/lock/subsys/mysql-proxy
fi
}
stop() {
echo -n $"Stopping $prog: "
killproc -p $PROXY_PID -d 3 $prog
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
rm -f /var/lock/subsys/mysql-proxy
rm -f $PROXY_PID
fi
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
condrestart|try-restart)
if status -p $PROXY_PIDFILE $prog >&/dev/null; then
stop
start
fi
;;
status)
status -p $PROXY_PID $prog
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status|condrestart|try-restart}"
RETVAL=1
;;
esac
exit $RETVAL
```
将上述内容保存为/etc/rc.d/init.d/mysql-proxy给予执行权限而后加入到服务列表。
```
# chmod +x /etc/rc.d/init.d/mysql-proxy
# chkconfig --add mysql-proxy
```
#### 4.3 为服务脚本提供配置文件/etc/sysconfig/mysql-proxy内容如下所示
```
# Options for mysql-proxy
ADMIN_USER="admin"
ADMIN_PASSWORD="admin"
ADMIN_ADDRESS=""
ADMIN_LUA_SCRIPT="/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
PROXY_ADDRESS=""
PROXY_USER="mysql-proxy"
PROXY_OPTIONS="--daemon --log-level=info --log-use-syslog"
```
其中最后一行,需要按实际场景进行修改,例如:
```
PROXY_OPTIONS="--daemon --log-level=info --log-use-syslog --plugins=proxy --plugins=admin --proxy-backend-addresses=172.16.100.6:3306 --proxy-read-only-backend-addresses=172.16.100.7:3306 --proxy-lua-script=/usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua"
```
其中的proxy-backend-addresses选项和proxy-read-only-backend-addresses选项均可重复使用多次以实现指定多个读写服务器或只读服务器。
#### 4.4 mysql-proxy的配置选项
mysql-proxy的配置选项大致可分为帮助选项、管理选项、代理选项及应用程序选项几类下面一起去介绍它们。
```
--help
--help-admin
--help-proxy
--help-all ———— 以上四个选项均用于获取帮助信息;
--proxy-address=host:port ———— 代理服务监听的地址和端口;
--admin-address=host:port ———— 管理模块监听的地址和端口;
--proxy-backend-addresses=host:port ———— 后端mysql服务器的地址和端口
--proxy-read-only-backend-addresses=host:port ———— 后端只读mysql服务器的地址和端口
--proxy-lua-script=file_name ———— 完成mysql代理功能的Lua脚本
--daemon ———— 以守护进程模式启动mysql-proxy
--keepalive ———— 在mysql-proxy崩溃时尝试重启之
--log-file=/path/to/log_file_name ———— 日志文件名称;
--log-level=level ———— 日志级别;
--log-use-syslog ———— 基于syslog记录日志
--plugins=plugin,.. ———— 在mysql-proxy启动时加载的插件
--user=user_name ———— 运行mysql-proxy进程的用户
--defaults-file=/path/to/conf_file_name ———— 默认使用的配置文件路径;其配置段使用[mysql-proxy]标识;
--proxy-skip-profiling ———— 禁用profile
--pid-file=/path/to/pid_file_name ———— 进程文件名;
```
5、复制如下内容建立admin.lua文件将其保存至/usr/local/mysql-proxy/share/doc/mysql-proxy/目录中。
```
--[[ $%BEGINLICENSE%$
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; version 2 of the
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA
$%ENDLICENSE%$ --]]
function set_error(errmsg)
proxy.response = {
type = proxy.MYSQLD_PACKET_ERR,
errmsg = errmsg or "error"
}
end
function read_query(packet)
if packet:byte() ~= proxy.COM_QUERY then
set_error("[admin] we only handle text-based queries (COM_QUERY)")
return proxy.PROXY_SEND_RESULT
end
local query = packet:sub(2)
local rows = { }
local fields = { }
if query:lower() == "select * from backends" then
fields = {
{ name = "backend_ndx",
type = proxy.MYSQL_TYPE_LONG },
{ name = "address",
type = proxy.MYSQL_TYPE_STRING },
{ name = "state",
type = proxy.MYSQL_TYPE_STRING },
{ name = "type",
type = proxy.MYSQL_TYPE_STRING },
{ name = "uuid",
type = proxy.MYSQL_TYPE_STRING },
{ name = "connected_clients",
type = proxy.MYSQL_TYPE_LONG },
}
for i = 1, #proxy.global.backends do
local states = {
"unknown",
"up",
"down"
}
local types = {
"unknown",
"rw",
"ro"
}
local b = proxy.global.backends[i]
rows[#rows + 1] = {
i,
b.dst.name, -- configured backend address
states[b.state + 1], -- the C-id is pushed down starting at 0
types[b.type + 1], -- the C-id is pushed down starting at 0
b.uuid, -- the MySQL Server's UUID if it is managed
b.connected_clients -- currently connected clients
}
end
elseif query:lower() == "select * from help" then
fields = {
{ name = "command",
type = proxy.MYSQL_TYPE_STRING },
{ name = "description",
type = proxy.MYSQL_TYPE_STRING },
}
rows[#rows + 1] = { "SELECT * FROM help", "shows this help" }
rows[#rows + 1] = { "SELECT * FROM backends", "lists the backends and their state" }
else
set_error("use 'SELECT * FROM help' to see the supported commands")
return proxy.PROXY_SEND_RESULT
end
proxy.response = {
type = proxy.MYSQLD_PACKET_OK,
resultset = {
fields = fields,
rows = rows
}
}
return proxy.PROXY_SEND_RESULT
end
```
#### 6、测试
6.1 管理功能测试
```
# mysql -uadmin -padmin -h172.16.100.107 --port=4041
```
```
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.0.99-agent-admin
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> SELECT * FROM backends;
+-------------+-------------------+-------+------+------+-------------------+
| backend_ndx | address | state | type | uuid | connected_clients |
+-------------+-------------------+-------+------+------+-------------------+
| 1 | 172.16.100.6:3306 | up | rw | NULL | 0 |
| 2 | 172.16.100.7:3306 | up | ro | NULL | 0 |
+-------------+-------------------+-------+------+------+-------------------+
2 rows in set (0.00 sec)
```
6.2 读写分离测试
```
# mysql -uroot -pmagedu.com -h172.16.100.107 --port=4040
```
下面的读写分享脚本是由mysql-proxy-0.8.3提供,将其复制保存为/usr/lib/mysql-proxy/lua/proxy/rw-splitting.lua就可以启动服务了。
```
--[[ $%BEGINLICENSE%$
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; version 2 of the
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA
$%ENDLICENSE%$ --]]
---
-- a flexible statement based load balancer with connection pooling
--
-- * build a connection pool of min_idle_connections for each backend and maintain
-- its size
-- *
--
--
local commands = require("proxy.commands")
local tokenizer = require("proxy.tokenizer")
local lb = require("proxy.balance")
local auto_config = require("proxy.auto-config")
--- config
--
-- connection pool
if not proxy.global.config.rwsplit then
proxy.global.config.rwsplit = {
min_idle_connections = 4,
max_idle_connections = 8,
is_debug = false
}
end
---
-- read/write splitting sends all non-transactional SELECTs to the slaves
--
-- is_in_transaction tracks the state of the transactions
local is_in_transaction = false
-- if this was a SELECT SQL_CALC_FOUND_ROWS ... stay on the same connections
local is_in_select_calc_found_rows = false
---
-- get a connection to a backend
--
-- as long as we don't have enough connections in the pool, create new connections
--
function connect_server()
local is_debug = proxy.global.config.rwsplit.is_debug
-- make sure that we connect to each backend at least ones to
-- keep the connections to the servers alive
--
-- on read_query we can switch the backends again to another backend
if is_debug then
print()
print("[connect_server] " .. proxy.connection.client.src.name)
end
local rw_ndx = 0
-- init all backends
for i = 1, #proxy.global.backends do
local s = proxy.global.backends[i]
local pool = s.pool -- we don't have a username yet, try to find a connections which is idling
local cur_idle = pool.users[""].cur_idle_connections
pool.min_idle_connections = proxy.global.config.rwsplit.min_idle_connections
pool.max_idle_connections = proxy.global.config.rwsplit.max_idle_connections
if is_debug then
print(" [".. i .."].connected_clients = " .. s.connected_clients)
print(" [".. i .."].pool.cur_idle = " .. cur_idle)
print(" [".. i .."].pool.max_idle = " .. pool.max_idle_connections)
print(" [".. i .."].pool.min_idle = " .. pool.min_idle_connections)
print(" [".. i .."].type = " .. s.type)
print(" [".. i .."].state = " .. s.state)
end
-- prefer connections to the master
if s.type == proxy.BACKEND_TYPE_RW and
s.state ~= proxy.BACKEND_STATE_DOWN and
cur_idle < pool.min_idle_connections then
proxy.connection.backend_ndx = i
break
elseif s.type == proxy.BACKEND_TYPE_RO and
s.state ~= proxy.BACKEND_STATE_DOWN and
cur_idle < pool.min_idle_connections then
proxy.connection.backend_ndx = i
break
elseif s.type == proxy.BACKEND_TYPE_RW and
s.state ~= proxy.BACKEND_STATE_DOWN and
rw_ndx == 0 then
rw_ndx = i
end
end
if proxy.connection.backend_ndx == 0 then
if is_debug then
print(" [" .. rw_ndx .. "] taking master as default")
end
proxy.connection.backend_ndx = rw_ndx
end
-- pick a random backend
--
-- we someone have to skip DOWN backends
-- ok, did we got a backend ?
if proxy.connection.server then
if is_debug then
print(" using pooled connection from: " .. proxy.connection.backend_ndx)
end
-- stay with it
return proxy.PROXY_IGNORE_RESULT
end
if is_debug then
print(" [" .. proxy.connection.backend_ndx .. "] idle-conns below min-idle")
end
-- open a new connection
end
---
-- put the successfully authed connection into the connection pool
--
-- @param auth the context information for the auth
--
-- auth.packet is the packet
function read_auth_result( auth )
if is_debug then
print("[read_auth_result] " .. proxy.connection.client.src.name)
end
if auth.packet:byte() == proxy.MYSQLD_PACKET_OK then
-- auth was fine, disconnect from the server
proxy.connection.backend_ndx = 0
elseif auth.packet:byte() == proxy.MYSQLD_PACKET_EOF then
-- we received either a
--
-- * MYSQLD_PACKET_ERR and the auth failed or
-- * MYSQLD_PACKET_EOF which means a OLD PASSWORD (4.0) was sent
print("(read_auth_result) ... not ok yet");
elseif auth.packet:byte() == proxy.MYSQLD_PACKET_ERR then
-- auth failed
end
end
---
-- read/write splitting
function read_query( packet )
local is_debug = proxy.global.config.rwsplit.is_debug
local cmd = commands.parse(packet)
local c = proxy.connection.client
local r = auto_config.handle(cmd)
if r then return r end
local tokens
local norm_query
-- looks like we have to forward this statement to a backend
if is_debug then
print("[read_query] " .. proxy.connection.client.src.name)
print(" current backend = " .. proxy.connection.backend_ndx)
print(" client default db = " .. c.default_db)
print(" client username = " .. c.username)
if cmd.type == proxy.COM_QUERY then
print(" query = " .. cmd.query)
end
end
if cmd.type == proxy.COM_QUIT then
-- don't send COM_QUIT to the backend. We manage the connection
-- in all aspects.
proxy.response = {
type = proxy.MYSQLD_PACKET_OK,
}
if is_debug then
print(" (QUIT) current backend = " .. proxy.connection.backend_ndx)
end
return proxy.PROXY_SEND_RESULT
end
-- COM_BINLOG_DUMP packet can't be balanced
--
-- so we must send it always to the master
if cmd.type == proxy.COM_BINLOG_DUMP then
-- if we don't have a backend selected, let's pick the master
--
if proxy.connection.backend_ndx == 0 then
proxy.connection.backend_ndx = lb.idle_failsafe_rw()
end
return
end
proxy.queries:append(1, packet, { resultset_is_needed = true })
-- read/write splitting
--
-- send all non-transactional SELECTs to a slave
if not is_in_transaction and
cmd.type == proxy.COM_QUERY then
tokens = tokens or assert(tokenizer.tokenize(cmd.query))
local stmt = tokenizer.first_stmt_token(tokens)
if stmt.token_name == "TK_SQL_SELECT" then
is_in_select_calc_found_rows = false
local is_insert_id = false
for i = 1, #tokens do
local token = tokens[i]
-- SQL_CALC_FOUND_ROWS + FOUND_ROWS() have to be executed
-- on the same connection
-- print("token: " .. token.token_name)
-- print(" val: " .. token.text)
if not is_in_select_calc_found_rows and token.token_name == "TK_SQL_SQL_CALC_FOUND_ROWS" then
is_in_select_calc_found_rows = true
elseif not is_insert_id and token.token_name == "TK_LITERAL" then
local utext = token.text:upper()
if utext == "LAST_INSERT_ID" or
utext == "@@INSERT_ID" then
is_insert_id = true
end
end
-- we found the two special token, we can't find more
if is_insert_id and is_in_select_calc_found_rows then
break
end
end
-- if we ask for the last-insert-id we have to ask it on the original
-- connection
if not is_insert_id then
local backend_ndx = lb.idle_ro()
if backend_ndx > 0 then
proxy.connection.backend_ndx = backend_ndx
end
else
print(" found a SELECT LAST_INSERT_ID(), staying on the same backend")
end
end
end
-- no backend selected yet, pick a master
if proxy.connection.backend_ndx == 0 then
-- we don't have a backend right now
--
-- let's pick a master as a good default
--
proxy.connection.backend_ndx = lb.idle_failsafe_rw()
end
-- by now we should have a backend
--
-- in case the master is down, we have to close the client connections
-- otherwise we can go on
if proxy.connection.backend_ndx == 0 then
return proxy.PROXY_SEND_QUERY
end
local s = proxy.connection.server
-- if client and server db don't match, adjust the server-side
--
-- skip it if we send a INIT_DB anyway
if cmd.type ~= proxy.COM_INIT_DB and
c.default_db and c.default_db ~= s.default_db then
print(" server default db: " .. s.default_db)
print(" client default db: " .. c.default_db)
print(" syncronizing")
proxy.queries:prepend(2, string.char(proxy.COM_INIT_DB) .. c.default_db, { resultset_is_needed = true })
end
-- send to master
if is_debug then
if proxy.connection.backend_ndx > 0 then
local b = proxy.global.backends[proxy.connection.backend_ndx]
print(" sending to backend : " .. b.dst.name);
print(" is_slave : " .. tostring(b.type == proxy.BACKEND_TYPE_RO));
print(" server default db: " .. s.default_db)
print(" server username : " .. s.username)
end
print(" in_trans : " .. tostring(is_in_transaction))
print(" in_calc_found : " .. tostring(is_in_select_calc_found_rows))
print(" COM_QUERY : " .. tostring(cmd.type == proxy.COM_QUERY))
end
return proxy.PROXY_SEND_QUERY
end
---
-- as long as we are in a transaction keep the connection
-- otherwise release it so another client can use it
function read_query_result( inj )
local is_debug = proxy.global.config.rwsplit.is_debug
local res = assert(inj.resultset)
local flags = res.flags
if inj.id ~= 1 then
-- ignore the result of the USE <default_db>
-- the DB might not exist on the backend, what do do ?
--
if inj.id == 2 then
-- the injected INIT_DB failed as the slave doesn't have this DB
-- or doesn't have permissions to read from it
if res.query_status == proxy.MYSQLD_PACKET_ERR then
proxy.queries:reset()
proxy.response = {
type = proxy.MYSQLD_PACKET_ERR,
errmsg = "can't change DB ".. proxy.connection.client.default_db ..
" to on slave " .. proxy.global.backends[proxy.connection.backend_ndx].dst.name
}
return proxy.PROXY_SEND_RESULT
end
end
return proxy.PROXY_IGNORE_RESULT
end
is_in_transaction = flags.in_trans
local have_last_insert_id = (res.insert_id and (res.insert_id > 0))
if not is_in_transaction and
not is_in_select_calc_found_rows and
not have_last_insert_id then
-- release the backend
proxy.connection.backend_ndx = 0
elseif is_debug then
print("(read_query_result) staying on the same backend")
print(" in_trans : " .. tostring(is_in_transaction))
print(" in_calc_found : " .. tostring(is_in_select_calc_found_rows))
print(" have_insert_id : " .. tostring(have_last_insert_id))
end
end
---
-- close the connections if we have enough connections in the pool
--
-- @return nil - close connection
-- IGNORE_RESULT - store connection in the pool
function disconnect_client()
local is_debug = proxy.global.config.rwsplit.is_debug
if is_debug then
print("[disconnect_client] " .. proxy.connection.client.src.name)
end
-- make sure we are disconnection from the connection
-- to move the connection into the pool
proxy.connection.backend_ndx = 0
end
```

View file

@ -0,0 +1,7 @@
Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
Repeatable read (可重复读):可避免脏读、不可重复读的发生。
Read committed (读已提交):可避免脏读的发生。
Read uncommitted (读未提交):最低级别,任何情况都无法保证

View file

@ -0,0 +1,20 @@
### 查看数据库的隔离级别
```
mysql> select @@tx_isolation;
```
### 去查看先当前库的线程情况
```
mysql> show processlist;
```
没有看到正在执行的慢SQL记录线程再去查看innodb的事务表INNODB_TRX看下里面是否有正在锁定的事务线程看看ID是否在show full processlist里面的sleep线程中如果是就证明这个sleep的线程事务一直没有commit或者rollback而是卡住了我们需要手动kill掉。
```
mysql> SELECT * FROM information_schema.INNODB_TRX;
```
如果有记录,则找到trx_mysql_thread_id这个字段对应的id, 将其kill掉。假如id=100
```
mysql->kill 100
SELECT CONCAT_WS('','kill',' ',t.trx_mysql_thread_id,';')a FROM information_schema.INNODB_TRX t;
```

View file

@ -0,0 +1,37 @@
### InnoDB
```
InnoDB是一个事务型的存储引擎有行级锁定和外键约束
Innodb引擎提供了对数据库ACID事务的支持并且实现了SQL标准的四种隔离级别关于数据库事务与其隔离级别的内容请见数据库事务与其隔离级别这类型的文章。该引擎还提供了行级锁和外键约束它的设计目标是处理大容量数据库系统它本身其实就是基于MySQL后台的完整数据库系统MySQL运行时Innodb会在内存中建立缓冲池用于缓冲数据和索引。但是该引擎不支持FULLTEXT类型的索引而且它没有保存表的行数当SELECT COUNT(*) FROM TABLE时需要扫描全表。当需要使用数据库事务时该引擎当然是首选。由于锁的粒度更小写操作不会锁定全表所以在并发较高时使用Innodb引擎会提升效率。但是使用行级锁也不是绝对的如果在执行一个SQL语句时MySQL不能确定要扫描的范围InnoDB表同样会锁全表。
```
#### 适用场景
```
1经常更新的表适合处理多重并发的更新请求。
2支持事务。
3可以从灾难中恢复通过bin-log日志等
4外键约束。只有他支持外键。
5支持自动增加列属性auto_increment。
```
#### 其他
```
1InnoDB给MySQL提供了具有提交、回滚和崩溃恢复能力的事务安全ACID兼容存储引擎。
2InnoDB锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读这些特色增加了多用户部署和性能。没有在InnoDB中扩大锁定的需要因为在InnoDB中行级锁定适合非常小的空间。
3InnoDB也支持FOREIGN KEY强制。在SQL查询中你可以自由地将InnoDB类型的表与其它MySQL的表的类型混合起来甚至在同一个查询中也可以混合。
4InnoDB是为处理巨大数据量时的最大性能设计它的CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。
5InnoDB被用来在众多需要高性能的大型数据库站点上产生。
```
### MyISAM
```
MyIASM是MySQL默认的引擎但是它没有提供对数据库事务的支持也不支持行级锁和外键因此当INSERT(插入)或UPDATE(更新)数据时即写操作需要锁定整个表,效率便会低一些。
MyIsam 存储引擎独立于操作系统也就是可以在windows上使用也可以比较简单的将数据转移到linux操作系统上去。
意味着:引擎在创建表的时候,会创建三个文件,一个是.frm文件用于存储表的定义一个是.MYD文件用于存储表的数据另一个是.MYI文件存储的是索引。操作系统对大文件的操作是比较慢的这样将表分为三个文件那么.MYD这个文件单独来存放数据自然可以优化数据库的查询等操作。有索引管理和字段管理。MyISAM还使用一种表格锁定的机制来优化多个并发的读写操作其代价是你需要经常运行OPTIMIZE TABLE命令来恢复被更新机制所浪费的空间。
```
#### 适用场景
```
1不支持事务的设计但是并不代表着有事务操作的项目不能用MyIsam存储引擎可以在service层进行根据自己的业务需求进行相应的控制。
2不支持外键的表设计。
3查询速度很快如果数据库insert和update的操作比较多的话比较适用。
4整天 对表进行加锁的场景。
5MyISAM极度强调快速读取操作。
6MyIASM中存储了表的行数于是SELECT COUNT(*) FROM TABLE时只需要直接读取已经保存好的值而不需要进行全表扫描。如果表的读操作远远多于写操作且不需要数据库事务的支持那么MyIASM也是很好的选择。
```

View file

@ -0,0 +1,186 @@
使用Xtrabackup进行MySQL备份
一、安装
1、简介
Xtrabackup是由percona提供的mysql数据库备份工具据官方介绍这也是世界上惟一一款开源的能够对innodb和xtradb数据库进行热备的工具。特点
(1)备份过程快速、可靠;
(2)备份过程不会打断正在执行的事务;
(3)能够基于压缩等功能节约磁盘空间和流量;
(4)自动实现备份检验;
(5)还原速度快;
2、安装
其最新版的软件可从 http://www.percona.com/software/percona-xtrabackup/ 获得。本文基于RHEL5.8的系统因此直接下载相应版本的rpm包安装即可这里不再演示其过程。
二、备份的实现
1、完全备份
# innobackupex --user=DBUSER --password=DBUSERPASS /path/to/BACKUP-DIR/
如果要使用一个最小权限的用户进行备份,则可基于如下命令创建此类用户:
mysql> CREATE USER bkpuser@localhost IDENTIFIED BY s3cret;
mysql> REVOKE ALL PRIVILEGES, GRANT OPTION FROM bkpuser;
mysql> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO bkpuser@localhost;
mysql> FLUSH PRIVILEGES;
使用innobakupex备份时其会调用xtrabackup备份所有的InnoDB表复制所有关于表结构定义的相关文件(.frm)、以及MyISAM、MERGE、CSV和ARCHIVE表的相关文件同时还会备份触发器和数据库配置信息相关的文件。这些文件会被保存至一个以时间命令的目录中。
在备份的同时innobackupex还会在备份目录中创建如下文件
(1)xtrabackup_checkpoints —— 备份类型如完全或增量、备份状态如是否已经为prepared状态和LSN(日志序列号)范围信息;
每个InnoDB页(通常为16k大小)都会包含一个日志序列号即LSN。LSN是整个数据库系统的系统版本号每个页面相关的LSN能够表明此页面最近是如何发生改变的。
(2)xtrabackup_binlog_info —— mysql服务器当前正在使用的二进制日志文件及至备份这一刻为止二进制日志事件的位置。
(3)xtrabackup_binlog_pos_innodb —— 二进制日志文件及用于InnoDB或XtraDB表的二进制日志文件的当前position。
(4)xtrabackup_binary —— 备份中用到的xtrabackup的可执行文件
(5)backup-my.cnf —— 备份命令用到的配置选项信息;
在使用innobackupex进行备份时还可以使用--no-timestamp选项来阻止命令自动创建一个以时间命名的目录如此一来innobackupex命令将会创建一个BACKUP-DIR目录来存储备份数据。
2、准备(prepare)一个完全备份
一般情况下,在备份完成后,数据尚且不能用于恢复操作,因为备份的数据中可能会包含尚未提交的事务或已经提交但尚未同步至数据文件中的事务。因此,此时数据文件仍处理不一致状态。“准备”的主要作用正是通过回滚未提交的事务及同步已经提交的事务至数据文件也使得数据文件处于一致性状态。
innobakupex命令的--apply-log选项可用于实现上述功能。如下面的命令
# innobackupex --apply-log /path/to/BACKUP-DIR
如果执行正确,其最后输出的几行信息通常如下:
xtrabackup: starting shutdown with innodb_fast_shutdown = 1
120407 9:01:36 InnoDB: Starting shutdown...
120407 9:01:40 InnoDB: Shutdown completed; log sequence number 92036620
120407 09:01:40 innobackupex: completed OK!
在实现“准备”的过程中innobackupex通常还可以使用--use-memory选项来指定其可以使用的内存的大小默认通常为100M。如果有足够的内存可用可以多划分一些内存给prepare的过程以提高其完成速度。
3、从一个完全备份中恢复数据
注意恢复不用启动MySQL
innobackupex命令的--copy-back选项用于执行恢复操作其通过复制所有数据相关的文件至mysql服务器DATADIR目录中来执行恢复过程。innobackupex通过backup-my.cnf来获取DATADIR目录的相关信息。
# innobackupex --copy-back /path/to/BACKUP-DIR
如果执行正确,其输出信息的最后几行通常如下:
innobackupex: Starting to copy InnoDB log files
innobackupex: in '/backup/2012-04-07_08-17-03'
innobackupex: back to original InnoDB log directory '/mydata/data'
innobackupex: Finished copying back files.
120407 09:36:10 innobackupex: completed OK!
请确保如上信息的最行一行出现“innobackupex: completed OK!”。
当数据恢复至DATADIR目录以后还需要确保所有数据文件的属主和属组均为正确的用户如mysql否则在启动mysqld之前还需要事先修改数据文件的属主和属组。如
# chown -R mysql:mysql /mydata/data/
4、使用innobackupex进行增量备份
每个InnoDB的页面都会包含一个LSN信息每当相关的数据发生改变相关的页面的LSN就会自动增长。这正是InnoDB表可以进行增量备份的基础即innobackupex通过备份上次完全备份之后发生改变的页面来实现。
要实现第一次增量备份,可以使用下面的命令进行:
# innobackupex --incremental /backup --incremental-basedir=BASEDIR
其中BASEDIR指的是完全备份所在的目录此命令执行结束后innobackupex命令会在/backup目录中创建一个新的以时间命名的目录以存放所有的增量备份数据。另外在执行过增量备份之后再一次进行增量备份时其--incremental-basedir应该指向上一次的增量备份所在的目录。
需要注意的是增量备份仅能应用于InnoDB或XtraDB表对于MyISAM表而言执行增量备份时其实进行的是完全备份。
“准备”(prepare)增量备份与整理完全备份有着一些不同,尤其要注意的是:
(1)需要在每个备份(包括完全和各个增量备份)上,将已经提交的事务进行“重放”。“重放”之后,所有的备份数据将合并到完全备份上。
(2)基于所有的备份将未提交的事务进行“回滚”。
于是,操作就变成了:
# innobackupex --apply-log --redo-only BASE-DIR
接着执行:
# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-1
而后是第二个增量:
# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-2
其中BASE-DIR指的是完全备份所在的目录而INCREMENTAL-DIR-1指的是第一次增量备份的目录INCREMENTAL-DIR-2指的是第二次增量备份的目录其它依次类推即如果有多次增量备份每一次都要执行如上操作
5、Xtrabackup的“流”及“备份压缩”功能
Xtrabackup对备份的数据文件支持“流”功能即可以将备份的数据通过STDOUT传输给tar程序进行归档而不是默认的直接保存至某备份目录中。要使用此功能仅需要使用--stream选项即可。如
# innobackupex --stream=tar /backup | gzip > /backup/`date +%F_%H-%M-%S`.tar.gz
甚至也可以使用类似如下命令将数据备份至其它服务器:
# innobackupex --stream=tar /backup | ssh user@www.magedu.com "cat - > /backups/`date +%F_%H-%M-%S`.tar"
此外,在执行本地备份时,还可以使用--parallel选项对多个文件进行并行复制。此选项用于指定在复制时启动的线程数目。当然在实际进行备份时要利用此功能的便利性也需要启用innodb_file_per_table选项或共享的表空间通过innodb_data_file_path选项存储在多个ibdata文件中。对某一数据库的多个文件的复制无法利用到此功能。其简单使用方法如下
# innobackupex --parallel /path/to/backup
同时innobackupex备份的数据文件也可以存储至远程主机这可以使用--remote-host选项来实现
# innobackupex --remote-host=root@www.magedu.com /path/IN/REMOTE/HOST/to/backup
6、导入或导出单张表
默认情况下InnoDB表不能通过直接复制表文件的方式在mysql服务器之间进行移植即便使用了innodb_file_per_table选项。而使用Xtrabackup工具可以实现此种功能不过此时需要“导出”表的mysql服务器启用了innodb_file_per_table选项严格来说是要“导出”的表在其创建之前mysql服务器就启用了innodb_file_per_table选项并且“导入”表的服务器同时启用了innodb_file_per_table和innodb_expand_import选项。
(1)“导出”表
导出表是在备份的prepare阶段进行的因此一旦完全备份完成就可以在prepare过程中通过--export选项将某表导出了
# innobackupex --apply-log --export /path/to/backup
此命令会为每个innodb表的表空间创建一个以.exp结尾的文件这些以.exp结尾的文件则可以用于导入至其它服务器。
(2)“导入”表
要在mysql服务器上导入来自于其它服务器的某innodb表需要先在当前服务器上创建一个跟原表表结构一致的表而后才能实现将表导入
mysql> CREATE TABLE mytable (...) ENGINE=InnoDB;
然后将此表的表空间删除:
mysql> ALTER TABLE mydatabase.mytable DISCARD TABLESPACE;
接下来将来自于“导出”表的服务器的mytable表的mytable.ibd和mytable.exp文件复制到当前服务器的数据目录然后使用如下命令将其“导入”
mysql> ALTER TABLE mydatabase.mytable IMPORT TABLESPACE;
7、使用Xtrabackup对数据库进行部分备份
Xtrabackup也可以实现部分备份即只备份某个或某些指定的数据库或某数据库中的某个或某些表。但要使用此功能必须启用innodb_file_per_table选项即每张表保存为一个独立的文件。同时其也不支持--stream选项即不支持将数据通过管道传输给其它程序进行处理。
此外还原部分备份跟还原全部数据的备份也有所不同即你不能通过简单地将prepared的部分备份使用--copy-back选项直接复制回数据目录而是要通过导入表的方向来实现还原。当然有些情况下部分备份也可以直接通过--copy-back进行还原但这种方式还原而来的数据多数会产生数据不一致的问题因此无论如何不推荐使用这种方式。
(1)创建部分备份
创建部分备份的方式有三种:正则表达式(--include), 枚举表文件(--tables-file)和列出要备份的数据库(--databases)。
(a)使用--include
使用--include时要求为其指定要备份的表的完整名称即形如databasename.tablename
# innobackupex --include='^mageedu[.]tb1' /path/to/backup
(b)使用--tables-file
此选项的参数需要是一个文件名,此文件中每行包含一个要备份的表的完整名称;如:
# echo -e 'mageedu.tb1\nmageedu.tb2' > /tmp/tables.txt
# innobackupex --tables-file=/tmp/tables.txt /path/to/backup
(c)使用--databases
此选项接受的参数为数据名,如果要指定多个数据库,彼此间需要以空格隔开;同时,在指定某数据库时,也可以只指定其中的某张表。此外,此选项也可以接受一个文件为参数,文件中每一行为一个要备份的对象。如:
# innobackupex --databases="mageedu testdb" /path/to/backup
(2)整理(preparing)部分备份
prepare部分备份的过程类似于导出表的过程要使用--export选项进行
# innobackupex --apply-log --export /pat/to/partial/backup
此命令执行过程中innobackupex会调用xtrabackup命令从数据字典中移除缺失的表因此会显示出许多关于“表不存在”类的警告信息。同时也会显示出为备份文件中存在的表创建.exp文件的相关信息。
(3)还原部分备份
还原部分备份的过程跟导入表的过程相同。当然也可以通过直接复制prepared状态的备份直接至数据目录中实现还原不要此时要求数据目录处于一致状态。

165
数据库/mysql/mysql.html Normal file
View file

@ -0,0 +1,165 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="tool" content="leanote-desktop-app">
<title>mysql</title>
<style>
*{font-family:"lucida grande","lucida sans unicode",lucida,helvetica,"Hiragino Sans GB","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;}
body {
margin: 0;
}
/*公用文字样式*/
h1{font-size:30px}h2{font-size:24px}h3{font-size:18px}h4{font-size:14px}
.note-container{
width:850px;
margin:auto;
padding: 10px 20px;
box-shadow: 1px 1px 10px #eee;
}
#title {
margin: 0;
}
table {
margin-bottom: 16px;
border-collapse: collapse;
}
table th, table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
table th {
font-weight: bold;
}
table tr {
background-color: none;
border-top: 1px solid #ccc;
}
table tr:nth-child(2n) {
background-color: rgb(247, 247, 249);
}
.mce-item-table, .mce-item-table td, .mce-item-table th, .mce-item-table caption {
border: 1px solid #ddd;
border-collapse: collapse;
padding: 6px 13px;
}
blockquote {
border-left-width:10px;
background-color:rgba(128,128,128,0.05);
border-top-right-radius:5px;
border-bottom-right-radius:5px;
padding:15px 20px;
border-left:5px solid rgba(128,128,128,0.075);
}
blockquote p {
margin-bottom:1.1em;
font-size:1em;
line-height:1.45
}
blockquote ul:last-child,blockquote ol:last-child {
margin-bottom:0
}
pre {
padding: 18px;
background-color: #f7f7f9;
border: 1px solid #e1e1e8;
border-radius: 3px;
display: block;
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
white-space: nowrap;
background-color: #f9f2f4;
border-radius: 4px;
}
.footnote {
vertical-align: top;
position: relative;
top: -0.5em;
font-size: .8em;
}
hr {
margin:2em 0
}
img {
max-width:100%
}
pre {
word-break:break-word
}
p,pre,pre.prettyprint,blockquote {
margin:0 0 1.1em
}
hr {
margin:2em 0
}
img {
max-width:100%
}
.sequence-diagram,.flow-chart {
text-align:center;
margin-bottom:1.1em
}
.sequence-diagram text,.flow-chart text {
font-size:15px !important;
font-family:"Source Sans Pro",sans-serif !important
}
.sequence-diagram [fill="#ffffff"],.flow-chart [fill="#ffffff"] {
fill:#f6f6f6
}
.sequence-diagram [stroke="#000000"],.flow-chart [stroke="#000000"] {
stroke:#3f3f3f
}
.sequence-diagram text[stroke="#000000"],.flow-chart text[stroke="#000000"] {
stroke:none
}
.sequence-diagram [fill="#000"],.flow-chart [fill="#000"],.sequence-diagram [fill="#000000"],.flow-chart [fill="#000000"],.sequence-diagram [fill="black"],.flow-chart [fill="black"] {
fill:#3f3f3f
}
ul,ol {
margin-bottom:1.1em
}
ul ul,ol ul,ul ol,ol ol {
margin-bottom:1.1em
}
kbd {
padding:.1em .6em;
border:1px solid rgba(63,63,63,0.25);
-webkit-box-shadow:0 1px 0 rgba(63,63,63,0.25);
box-shadow:0 1px 0 rgba(63,63,63,0.25);
font-size:.7em;
font-family:sans-serif;
background-color:#fff;
color:#333;
border-radius:3px;
display:inline-block;
margin:0 .1em;
white-space:nowrap
}
.toc ul {
list-style-type:none;
margin-bottom:15px
}
</style>
<!-- 该css供自定义样式 -->
<link href="../leanote-html.css" rel="stylesheet">
</head>
<body>
<div class="note-container">
<h1 class="title" id="leanote-title">mysql</h1>
<div class="content-html" id="leanote-content"><div>grant</div><div>show grants for "username"@"host"</div><div><br></div><div>flush&nbsp;privileges;</div><div><div>用mysqldump工具导出表数据</div><div>mysqldump&nbsp;-uiboxpaynew&nbsp;-p&nbsp;-h172.16.1.86&nbsp;-t&nbsp;--compact&nbsp;iboxpay&nbsp;sp_posts&nbsp;&gt;/tmp/sp_posts.sql</div></div><div>//-u用户-p密码-h主机-t表数据--compact去掉注释iboxpay数据库sp_posts表-d表结构</div><div><br></div><div><br></div><div>备库同步</div><div><div>mysql&nbsp;-e&nbsp;"show&nbsp;databases;"&nbsp;-uroot&nbsp;-p'password'&nbsp;|&nbsp;grep&nbsp;-Ev&nbsp;"Database|information_schema|mysql|sys|performance_schema|test"|&nbsp;xargs&nbsp;mysqldump&nbsp;-uroot&nbsp;-p'password'&nbsp;&nbsp;--databases&nbsp;-R&gt;&nbsp;/tmp/aaa.sql</div><p><br></p></div></div>
</div>
<!-- 该js供其它处理 -->
<script src="../leanote-html.js"></script>
</body>
</html>

View file

@ -0,0 +1,29 @@
mysqladmin工具
mysqladmin [options] command [arg] [command[arg]] .....
command
create DB_Name 创建空数据库
-e直接返回
drop DB_Name 删除数据库
debug 打开调试日志并记录与error log中
status输出简要状态信息
-sleep # 指定显示延迟
-count # 指定批次
extended-status:输出mysq的各状态变量及数值相当于执行“mysql> show global status”
flush-hosts:清空主机相关的缓存DNS解析缓存此前因为连接错误次数过多而被拒绝访问mysqld的主机列表
flush-logs日志滚动主要是二进制日志和中继日志
refresh相当于同时使用flush-logs和flush-hosts
flush-privileges通知服务器重读授权表
reload重载授权表
flush-status重置状态变量的值
flush-tables关闭当前打开的表文件句柄
flush-threads清空线程缓存
kill杀死指定的线程可以一次杀死多个线程以逗号分隔但不能有多余空格
password修改指定用户的密码
processlist 线程列表
shutdown关闭mysqld进程
start-slave 启动从服务器进程
stop-slave 关闭从服务器进程
variables显示mysql的各服务器进程

View file

@ -0,0 +1,48 @@
1、在两台服务器上各自建立一个具有复制权限的用户
2、修改配置文件
# 主服务器A上
[mysqld]
server-id = 10
log-bin = mysql-bin
relay-log = relay-mysql
auto-increment-offset = 2
auto-increment-increment = 1
# 主服务器B上
[mysqld]
server-id = 20
log-bin = mysql-bin
relay-log = relay-mysql
auto-increment-increment = 2 # 起始值
auto-increment-offset = 2 # 步长
3、如果此时两台服务器均为新建立且无其它写入操作各服务器只需记录当前自己二进制日志文件及事件位置以之作为另外的服务器复制起始位置即可
serverA|mysql> SHOW MASTER STATUS\G
************************** 1. row ***************************
File: mysql-bin.000001
Position: 710
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)
server2|mysql> SHOW MASTER STATUS\G
mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
File: mysql-bin.000003
Position: 811
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)
4、各服务器接下来指定对另一台服务器为自己的主服务器即可
serverA|mysql> CHANGE MASTER TO ...,MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=811
serverB|mysql> CHANGE MASTER TO ...,MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=710
多主,且高可用的解决方案:
MMMMulti Master MySQL
MHAMySQL HA

View file

@ -0,0 +1,16 @@
二进制文件的字段说明
1、事件发生的日期和时间
2、服务器id
3、时间结束位置
4、事件类型
5、原服务器生成此事件时的线程id查看线程 [交互]show processlist
6、语句的时间戳和写入二进制文件的时间差
7、错误代码
8、事件内容
9、时间位置相当于下一个事件
查看二进制文件 mysqlbinlog binlogfile
查看日志偏移点 [交互]show master status;
二进制日志滚动 [交互]flush logs;
查看从指定偏移开始的日志 mysqlbinlog --start-position=偏移量 binlogfile
查看指定事件的日志 [交互]show binlog events in logfile

View file

@ -0,0 +1,5 @@
1、删除所有匿名用户 drop user ''@'localhost';
2、为所有root用户设定密码
[交互]set password for username@hosr = password('密码');
[交互]update mysql.user set password = password('密码') where user = 'root'; flush privileges;
mysqladmin -uusername -hhost password '密码' -p; mysqladmin -uusername -hhost -p flush-privileges

View file

@ -0,0 +1,56 @@
%:匹配任意长度任意字符
_:匹配任意单个字符
/*...*/:注释
数据库支持的所有服务器选项列表 mysqld --help --verbose
1、显示musqld使用配置文件的方式
2、显示mysqld启动时可用的选项通常为长选项
3、显示mysqld的配置文件中可用的配置变量
# 可以使用like子句
数据库变量 [交互]show variables;
数据库全局变量 [交互]show global variables;
数据库会话变量 [交互]show session variables;
数据库某个变量 [交互]select @@[global|session].variables_name;
查看全局变量 [交互]select * from information_schema.GLOBAL_VARIABLES where VARIABLE_NAME='SOME_VARIABLE_NAME';
查看会话变量 [交互]select * from information_schema.SESSION_VARIABLES where VARIABLE_NAME='SOME_VARIABLE_NAME';
修改变量值 [交互]set [global|session] variables_name="值"
数据库状态 [交互]show status;
数据库全局状态 [交互]show global status;
数据库状态 [交互]show session status;
查看数据库支持的引擎及引擎特性 [交互]show engines;
[交互]help contents 所有支持的帮助信息
[交互]help 关键字 获取特定的帮助信息
[交互]\. /path/to/sqlscript 执行sql脚本
[交互]\q 退出
[交互]\ help
[交互]\c 中断输入
[交互]\g 语句分隔符(无论是否是;
[交互]\G 以行形式显示执行结果
[交互]\! 执行shell命令
[交互]\s status
快捷键
ctrl+w删除光标前的单词
ctrl+u删除光标之前的所有字符
ctrl+y粘贴之前删除的内容
ctrl+a移动光标到行首
ctrl+e移动光标到行尾
mysql客户端连接进入服务器
-e sql不登陆数据库显示sql执行内容
--compress 压缩
-H或--html结果显示为html
-X或--xml结果显示xml
--safe-update拒绝使用无where子句的update或delete语句

View file

@ -0,0 +1,248 @@
MySQL有内置的SQL模型SQL_MODE用来定义字符超出的操作和模仿别的数据库的类型通过修改全局变量
常用的模式有:
TRADITIONAL 使用传统模式
STRICT_TRANS_TABLES 仅对支持事务的表的严格模式
STRICT_ALL_TABLES 对所有表使用严格模式
设定服务器变量的值:通常仅用于支持动态的变量
支持修改的服务器变量
动态变量可以在MySQL运行时修改
静态变量:与配置文件中修改其值,并重启后方能生效
服务器变量从其生效范围来讲,分两类
全局变量:服务器级别,修改之后仅对新建立的会话生效
回话变量:会话级别,仅对当前会话有效
会话建立时,从全局继承各变量
查看服务器变量
mysql> show [{global|session}] variables [like ''];
mysql> select @@{globa|session}.variable_name
mysql> mysql> select * from information_schema.GLOBAL_VARIABLES where VARIABLE_NAME='SOME_VARIABLE_NAME'; 查看全局变量
mysql> mysql> select * from information_schema.SESSION_VARIABLES where VARIABLE_NAME='SOME_VARIABLE_NAME'; 查看会话变量
修改变量:
前提:默认仅管理员有权限修改全局变量
mysql> set {global|session} variable_name='value';
注意无论是全局还是会话级别的动态变量修改在重启mysql后都会失效想永久有效可以定义在配置文件中的响应段中[mysqld]
数据库:
创建数据库
create database
CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
[[DEFAULT] CHARACTER SET [=] charset_name 字符集
| [DEFAULT] COLLATE [=] collation_name 排序方式]
删除数据库
DROP {DATABASE | SCHEMA} [IF EXISTS] db_name
修改数据库的字符集和排序字符以及数据字典
ALTER {DATABASE | SCHEMA} [db_name]
[[DEFAULT] CHARACTER SET [=] charset_name 字符集
| [DEFAULT] COLLATE [=] collation_name 排序方式]
ALTER {DATABASE | SCHEMA} db_name
UPGRADE DATA DIRECTORY NAME
表:
创建表:第一种方式
CREATE [TEMPORARY临时表保存在内存中] TABLE [IF NOT EXISTS] tbl_name
(create_definition,...)
[table_options]
(create_definition,...)
字段的定义:字段名、类型和类型修饰符
键、索引和约束
primary keyunique keyforeign keycheck
{index|key}
[table_options]
engine [=] engine_name
AUTO_INCREMENT [=] value 指定AUTO_INCREMENT的起始值
[DEFAULT] CHARACTER SET [=] charset_name 指定默认字符集
CHECKSUM [=] {0 | 1} 是否使用校验值
[DEFAULT] COLLATE [=] collation_name 排序规则
COMMENT [=] 'string' 注释
DELAY_KEY_WRITE [=] {0 | 1} 是否启用键延迟写入
ROW_FORMAT [=] {DEFAULT默认|DYNAMIC动态|FIXED静态|COMPRESSED压缩|REDUNDANT冗余|COMPACT紧致} 表格式
TABLESPACE tablespace_name [STORAGE {DISK|MEMORY|DEFAULT}] 表空间
myISAM引擎每表有三个文件都位于数据库目录
tb_name.frm:表结构定义
tb_name.MYD:数据文件
tb_name.MYI:索引文件
InnoDB表有两种存储方式
1、默认每表有一个独立文件和一个多表共享的文件
tb_name.frm表结构的定义位于数据库目录中
ibdata#共享的表空间文件默认位于数据目录datadir指向的目录中
2、独立的表空间
tb_name.frm每表有一个表结构文件
tb_name.ibd:一个独有的表空间文件
应该修改innodb_file_per_table为ON
表创建:第二种方式(复制表数据)
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
[(create_definition,...)]
[table_options]
select_statement
表创建:第三种方式(复制表结构)
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
{ LIKE old_tbl_name | (LIKE old_tbl_name) }
查看表的状态信息
show table status like table_name
删除表
DROP [TEMPORARY] TABLE [IF EXISTS]
tbl_name [, tbl_name] ...
[RESTRICT | CASCADE]
修改表:
ALTER TABLE tbl_name
[alter_specification [, alter_specification] ...]
修改字段定义:
插入新字段:
ADD [COLUMN] col_name column_definition
[FIRST | AFTER col_name ]
删除字段
DROP [COLUMN] col_name
修改字段
修改字段名称
CHANGE [COLUMN] old_col_name new_col_name column_definition
[FIRST|AFTER col_name]
修改字段类型及属性等
MODIFY [COLUMN] col_name column_definition
[FIRST | AFTER col_name]
表改名:
rename to|as new tb_name
修改存储引擎
engine =
指定排序标准的字段
ORDER BY col_name [, col_name] ...
MySQL的查询操作
单表查询:简单查询
多表查询:连续查询
联合查询
选择和投影
投影:挑选要符合的字段
选择:挑选符合条件的行
投影select 字段1字段2... from tb_name
selcet * from tb_name
选择select 字段1字段2,.... from tb_name where 子句
布尔条件表达式
布尔条件表达式操作符
= 等值比较
<=>:跟空值比较不会产生额外信息
<>:不等值
<:
<=
>
>=
IS NULL:是否为空
IS NOT NULL是否不空
LIKE支持的通配符%(任意长度的任意字符) _任意单个字符
RLIKEREGEXP支持使用正则表达式作为条件
IN判断某行的某一字段的值是否在给定的列表中
BETWEEN...AND....:判断指定的值是否位于指定的范围之间
组合条件测试
NOT |
AND &&
OR ||
排序
order by ‘排序字段’
默认为升序ASC
降序DESC
内置的聚合函数
sum
AVG平均值
MAX最大值
MIN最小值
COUNT个数统计
分组
group by
对分组的条件过滤
having
只返回有用的行
LIMIT
一个数为显示的行数
两个数字为偏移第一个数字行,显示第二个数字
select语句的执行流程
from clause --> where clause --> group by --> having clause -->order by --> select -->limit
select语句
distinct 重复的只显示一次
SQL_CACHE 缓存查询结果
SQL_NO_CACHE 不缓存查询结果
MySQL多表查询和子查询
联结查询事先将两张或者多张表join根据join的结果进行查询
cross join交叉联结
自然联结
等值联结:把相同的字段进行等值连接
外联结:
左外联接:只保留出现在左外连接元算之前(左边)的关系中的元组(以左表为准,)
left_tb LEFT JOIN right_tb ON 条件
右外联接:只保留出现在右外连接元算之后(右边)的关系中的元组(以右表为准)
left_tb RIGHT JOIN right_tb ON 条件
全外联接:
自联结:
别名AS
表别名:
字段别名
子查询:在查询中嵌套的查询
用于WHERE中的子查询
1.用于比较表达式中的子查询
子查询的返回值只能有一个
2.用于EXISTS中的子查询
判断存在与否
3.用于IN中的子查询
判断存在于指定列表中
用于FROM中子查询
select alias.col,....FROM(SELECT CLUSE) alias WHERE condition
MYSQL不擅长于子查询应该避免使用子查询
总结mysql的连接查询与子查询
联结:
交叉联结:
内联结:
外联结:
左外
右外
自联结
子查询:
用于where中的子查询
用于条件比较:
用于exists
用于IN中
用于FROM
MYSQL的联合查询
把两个或多个查询语句的结果合并成一个结果进行输出
select clauase union select clause union.....
索引
show indexs from tb_name 查看索引
alter table tb_name add index(字段)
创建索引
explain 解释命令,查看命令的执行过程
MYSQL视图虚表
存储下来的select语句
创建:
create view 视图名 as select语句
删除:
drop view 视图名

View file

@ -0,0 +1,84 @@
备份对象:
数据
配置文件
代码:存储过程,存储函数,触发器
OS相关的配置文件如crontab及相关脚本等
跟复制相关的配置:二进制日志文件
备份工具:
mysqldump逻辑备份工具
InnoDB热备、MyISAM温备、Aria温备
备份和恢复过程慢
mysqldumper多线程的mysqldump
难实现差异或增量备份
lvm-snapshot:
接近于热备的工具,因为要先请求全局锁,而后创建快照,并在创建快照完成后释放全局锁
使用cp、tar等工具物理备份备份与恢复速度快
难以实现增量备份,并且请求全局锁需要等待一段时间,在繁忙的服务器上更慢
select clause into outfile '/path/to/somefile'(备份)
load data infile '/path/from/somefile' (恢复)
部分备份工具,不会备份关系定义,仅备份表中的数据
逻辑备份工具快于mysqldump
Innobase商业备份工具Innobackup
Xtrabackup开源备份工具
InnoDB热备增量备份
MyISAM温备不支持增量
物理备份,速度快
mysqldump适用于数据量较小的情况(注意备份前要加锁)
mysqldump [options] [db_name] [tb_name]
备份单个数据库mysqldump -u 用户名 -h 主机 -p 数据库 > 备份文件
恢复时,如果目标库不存在,需要事先手动备份 mysql -u 用户名 -h 主机名 -p 数据库名 < 备份文件
备份所有库mysqldump --all-database > 备份文件
备份指定多个库: mysqldump --databases db1 db2
--lock-all-tables请求锁定所有表之后再备份对InnoDBMyISAMAria做温备
--single-transaction能够对InnoDB存储引擎实现热备
备份代码:
--events备份事件调度器代码
--routines备份存储过程与存储函数
--triggers备份触发器
备份时滚动日志
--flush-logs备份前、请求到锁之后滚动日志
复制时的同步位置标记
--master-data=[0|1|2]
0:不记录
1:记录为change master语句
2、记录为注释的change master语句
备份InnoDB存储引擎的数据库mysqldump --database 数据库 --single-transaction -flush-logs --master-data=2 > 数据文件
备份MyISAM存储引擎的数据库mysqldump --database 数据库 --lock-all-tables -flush-logs --master-data=2 > 数据文件
恢复时,查看备份文件中记录的标记位置(--master-data=2参数实现mysqlbinlog文件中的位置
关闭其他连接然后使用mysqlbinlog --start-position=标记位置 --end-position=结束标记 binlog文件 > 恢复文件
关闭binlog日志记录[交互]set session sql_log_bin=0
执行全量备份脚本及binlog中抽出的数据文件
开启binlog日志记录[交互]set session sql_log_bin=1
滚动二进制文件mysqldump flush-logs
lvm-snapshot:
step1: 锁表保证数据的一致性。flush table with read lock;
step2滚动日志flush logs;
step3查看master二进制当前的状态以便slave的复制使用或者其他的恢复使用。show master status;
step4: 为mysql数据目录所在的lvm做快照-p r只读 lvcreate -s -n sqlbak_snap -L 100M -p r /dev/sqlbak/sqlbck_lv
step5: 解锁unlock tables;
step6: 挂载快照卷到一个目录下
就可以读取里面的数据。当然也可以mv到其他的目录下用来恢复。
step7: 卸载快照卷。删除快照卷 lvremove /dev/sqlbak/sqlbck_lv

View file

@ -0,0 +1,165 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="tool" content="leanote-desktop-app">
<title>mysql导入导出</title>
<style>
*{font-family:"lucida grande","lucida sans unicode",lucida,helvetica,"Hiragino Sans GB","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;}
body {
margin: 0;
}
/*公用文字样式*/
h1{font-size:30px}h2{font-size:24px}h3{font-size:18px}h4{font-size:14px}
.note-container{
width:850px;
margin:auto;
padding: 10px 20px;
box-shadow: 1px 1px 10px #eee;
}
#title {
margin: 0;
}
table {
margin-bottom: 16px;
border-collapse: collapse;
}
table th, table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
table th {
font-weight: bold;
}
table tr {
background-color: none;
border-top: 1px solid #ccc;
}
table tr:nth-child(2n) {
background-color: rgb(247, 247, 249);
}
.mce-item-table, .mce-item-table td, .mce-item-table th, .mce-item-table caption {
border: 1px solid #ddd;
border-collapse: collapse;
padding: 6px 13px;
}
blockquote {
border-left-width:10px;
background-color:rgba(128,128,128,0.05);
border-top-right-radius:5px;
border-bottom-right-radius:5px;
padding:15px 20px;
border-left:5px solid rgba(128,128,128,0.075);
}
blockquote p {
margin-bottom:1.1em;
font-size:1em;
line-height:1.45
}
blockquote ul:last-child,blockquote ol:last-child {
margin-bottom:0
}
pre {
padding: 18px;
background-color: #f7f7f9;
border: 1px solid #e1e1e8;
border-radius: 3px;
display: block;
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
white-space: nowrap;
background-color: #f9f2f4;
border-radius: 4px;
}
.footnote {
vertical-align: top;
position: relative;
top: -0.5em;
font-size: .8em;
}
hr {
margin:2em 0
}
img {
max-width:100%
}
pre {
word-break:break-word
}
p,pre,pre.prettyprint,blockquote {
margin:0 0 1.1em
}
hr {
margin:2em 0
}
img {
max-width:100%
}
.sequence-diagram,.flow-chart {
text-align:center;
margin-bottom:1.1em
}
.sequence-diagram text,.flow-chart text {
font-size:15px !important;
font-family:"Source Sans Pro",sans-serif !important
}
.sequence-diagram [fill="#ffffff"],.flow-chart [fill="#ffffff"] {
fill:#f6f6f6
}
.sequence-diagram [stroke="#000000"],.flow-chart [stroke="#000000"] {
stroke:#3f3f3f
}
.sequence-diagram text[stroke="#000000"],.flow-chart text[stroke="#000000"] {
stroke:none
}
.sequence-diagram [fill="#000"],.flow-chart [fill="#000"],.sequence-diagram [fill="#000000"],.flow-chart [fill="#000000"],.sequence-diagram [fill="black"],.flow-chart [fill="black"] {
fill:#3f3f3f
}
ul,ol {
margin-bottom:1.1em
}
ul ul,ol ul,ul ol,ol ol {
margin-bottom:1.1em
}
kbd {
padding:.1em .6em;
border:1px solid rgba(63,63,63,0.25);
-webkit-box-shadow:0 1px 0 rgba(63,63,63,0.25);
box-shadow:0 1px 0 rgba(63,63,63,0.25);
font-size:.7em;
font-family:sans-serif;
background-color:#fff;
color:#333;
border-radius:3px;
display:inline-block;
margin:0 .1em;
white-space:nowrap
}
.toc ul {
list-style-type:none;
margin-bottom:15px
}
</style>
<!-- 该css供自定义样式 -->
<link href="../leanote-html.css" rel="stylesheet">
</head>
<body>
<div class="note-container">
<h1 class="title" id="leanote-title">mysql导入导出</h1>
<div class="content-html" id="leanote-content"><div><a href="http://www.cnblogs.com/jiunadianshi/articles/2022334.html" data-mce-href="http://www.cnblogs.com/jiunadianshi/articles/2022334.html">linux下导入、导出mysql数据库命令</a></div><div>一、导出数据库用mysqldump命令注意mysql的安装路径即此命令的路径</div><div>1、导出数据和表结构</div><div>mysqldump -u用户名 -p密码 数据库名 &gt; 数据库名.sql</div><div>#/usr/local/mysql/bin/&nbsp;&nbsp; mysqldump -uroot -p abc &gt; abc.sql</div><div>敲回车后会提示输入密码</div><div>2、只导出表结构</div><div>mysqldump -u用户名 -p密码 -d 数据库名 &gt; 数据库名.sql</div><div>#/usr/local/mysql/bin/&nbsp;&nbsp; mysqldump -uroot -p -d abc &gt; abc.sql</div><div>注:/usr/local/mysql/bin/&nbsp; ---&gt;&nbsp; mysql的data目录</div><div><br></div><div>二、导入数据库</div><div>1、首先建空数据库</div><div>mysql&gt;create database abc;</div><div>2、导入数据库</div><div>方法一:</div><div>1选择数据库</div><div>mysql&gt;use abc;</div><div>2设置数据库编码</div><div>mysql&gt;set names utf8;</div><div>3导入数据注意sql文件的路径</div><div>mysql&gt;source /home/abc/abc.sql;</div><div>方法二:</div><div>mysql -u用户名 -p密码 数据库名 &lt; 数据库名.sql</div><div>#mysql -uabc_f -p abc &lt; abc.sql</div><div>建议使用第二种方法导入。</div><div>注意有命令行模式有sql命令</div></div>
</div>
<!-- 该js供其它处理 -->
<script src="../leanote-html.js"></script>
</body>
</html>

View file

@ -0,0 +1,8 @@
### 原理
master节点将数据的改变记录到二进制binlog中slave会在一定时间间隔内对master二进制进行探测若发生改变那就开始一个io_thread请求master的二进制binlogmaster启动一个log dump线程发送二进制文件给slave并保存在slave节点的中继日志relay log中slave使用sql_thread从中继日志读取二进制文件在本地重放使得slave的数据与主节点保持一致最后io_thread和sql_thread休眠等待下次被唤醒
### 配置
1、主库my.cnf需要配置server_idbin_log(server_id唯一)
2、主节点创建一个具有复制权限的用户show master status查看master状态记录当前的log_bin文件和position
3、从节点my.cnf需要配置server_idread_only=true(防止在从节点执行update等操作但是对高权限的用户无效)
4、从节点执行change master to master_host=xxx,master_port=xxx,master_user=xxx,master_password=xxx,log_file='master-log-bin.xxxx',log_pos=xxx ,然后start slave可以通过show slave status\G查看状态

View file

@ -0,0 +1,55 @@
### 原因
2)1)、MySQL数据库主从同步延迟原理mysql主从同步原理主库针对写操作顺序写binlog从库单线程去主库顺序读”写操作的binlog”从库取到binlog在本地原样执行随机写来保证主从数据逻辑上一致。mysql的主从复制都是单线程的操作主库对所有DDL和DML产生binlogbinlog是顺序写所以效率很高slave的Slave_IO_Running线程到主库取日志效率比较高下一步问题来了slave的Slave_SQL_Running线程将主库的DDL和DML操作在slave实施。DML和DDL的IO操作是随即的不是顺序的成本高很多还可能slave上的其他查询产生lock争用由于Slave_SQL_Running也是单线程的所以一个DDL卡主了需要执行10分钟那么所有之后的DDL会等待这个DDL执行完才会继续执行这就导致了延时。有朋友会问“主库上那个相同的DDL也需要执行10分为什么slave会延时答案是master可以并发Slave_SQL_Running线程却不可以。
2)、MySQL数据库主从同步延迟是怎么产生的当主库的TPS并发较高时产生的DDL数量超过slave一个sql线程所能承受的范围那么延时就产生了当然还有就是可能与slave的大型query语句产生了锁等待。首要原因数据库在业务上读写压力太大CPU计算负荷大网卡负荷大硬盘随机IO太高次要原因读写binlog带来的性能影响网络传输延迟。
### 方案
1)、架构方面
1.业务的持久化层的实现采用分库架构mysql服务可平行扩展分散压力。
2.单个库读写分离,一主多从,主写从读,分散压力。这样从库压力比主库高,保护主库。
3.服务的基础架构在业务和mysql之间加入memcache或者redis的cache层。降低mysql的读压力。
4.不同业务的mysql物理上放在不同机器分散压力。
5.使用比主库更好的硬件设备作为slave总结mysql压力小延迟自然会变小。
2)、硬件方面
1.采用好服务器比如4u比2u性能明显好2u比1u性能明显好。
2.存储用ssd或者盘阵或者san提升随机写的性能。
3.主从间保证处在同一个交换机下面,并且是万兆环境。
总结,硬件强劲,延迟自然会变小。一句话,缩小延迟的解决方案就是花钱和花时间。
3)、mysql主从同步加速
1、sync_binlog在slave端设置为0
2、logs-slave-updates 从服务器从主服务器接收到的更新不记入它的二进制日志。
3、直接禁用slave端的binlog
4、slave端如果使用的存储引擎是innodbinnodb_flush_log_at_trx_commit =2
4)、从文件系统本身属性角度优化
master端修改linux、Unix文件系统中文件的etime属性 由于每当读文件时OS都会将读取操作发生的时间回写到磁盘上对于读操作频繁的数据库文件来说这是没必要的只会增加磁盘系统的负担影响I/O性能。可以通过设置文件系统的mount属性组织操作系统写atime信息在linux上的操作为打开/etc/fstab加上noatime参数/dev/sdb1 /data reiserfs noatime 1 2然后重新mount文件系统#mount -oremount /data
5)、同步参数调整主库是写对数据安全性较高比如sync_binlog=1innodb_flush_log_at_trx_commit = 1 之类的设置是需要的而slave则不需要这么高的数据安全完全可以讲sync_binlog设置为0或者关闭binloginnodb_flushlog也可以设置为0来提高sql的执行效率
1、sync_binlog=1 oMySQL提供一个sync_binlog参数来控制数据库的binlog刷到磁盘上去。默认sync_binlog=0表示MySQL不控制binlog的刷新由文件系统自己控制它的缓存的刷新。这时候的性能是最好的但是风险也是最大的。一旦系统Crash在binlog_cache中的所有binlog信息都会被丢失。
如果sync_binlog>0表示每sync_binlog次事务提交MySQL调用文件系统的刷新操作将缓存刷下去。最安全的就是sync_binlog=1了表示每次事务提交MySQL都会把binlog刷下去是最安全但是性能损耗最大的设置。这样的话在数据库所在的主机操作系统损坏或者突然掉电的情况下系统才有可能丢失1个事务的数据。但是binlog虽然是顺序IO但是设置sync_binlog=1多个事务同时提交同样很大的影响MySQL和IO性能。虽然可以通过group commit的补丁缓解但是刷新的频率过高对IO的影响也非常大。
对于高并发事务的系统来说“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多。所以很多MySQL DBA设置的sync_binlog并不是最安全的1而是2或者是0。这样牺牲一定的一致性可以获得更高的并发和性能。默认情况下并不是每次写入时都将binlog与硬盘同步。因此如果操作系统或机器(不仅仅是MySQL服务器)崩溃有可能binlog中最后的语句丢失了。要想防止这种情况你可以使用sync_binlog全局变量(1是最安全的值但也是最慢的)使binlog在每N次binlog写入后与硬盘同步。即使sync_binlog设置为1,出现崩溃时也有可能表内容和binlog内容之间存在不一致性。
2、innodb_flush_log_at_trx_commit 这个很管用抱怨Innodb比MyISAM慢 100倍那么你大概是忘了调整这个值。默认值1的意思是每一次事务提交或事务外的指令都需要把日志写入flush硬盘这是很费时的。特别是使用电池供电缓存Battery backed up cache时。设成2对于很多运用特别是从MyISAM表转过来的是可以的它的意思是不写入硬盘而是写入系统缓存。日志仍然会每秒flush到硬 盘所以你一般不会丢失超过1-2秒的更新。设成0会更快一点但安全方面比较差即使MySQL挂了也可能会丢失事务的数据。而值2只会在整个操作系统 挂了时才可能丢数据。
3、ls(1) 命令可用来列出文件的 atime、ctime 和 mtime。
atime 文件的access time 在读取文件或者执行文件时更改的ctime 文件的create time 在写入文件更改所有者权限或链接设置时随inode的内容更改而更改mtime 文件的modified time 在写入文件时随文件内容的更改而更改ls -lc filename 列出文件的 ctimels -lu filename 列出文件的 atimels -l filename 列出文件的 mtimestat filename 列出atimemtimectimeatime不一定在访问文件之后被修改因为使用ext3文件系统的时候如果在mount的时候使用了noatime参数那么就不会更新atime信息。这三个time stamp都放在 inode 中.如果mtime,atime 修改,inode 就一定会改, 既然 inode 改了,那ctime也就跟着改了.之所以在 mount option 中使用 noatime, 就是不想file system 做太多的修改, 而改善读取效能

View file

@ -0,0 +1,13 @@
备库B和主库A之间维持了一个长连接。主库A内部有一个线程专门用于服务备库B的这个长连接。一个事务日志同步的完整过程如下
1.在备库B上通过change master命令设置主库A的IP、端口、用户名、密码以及要从哪个位置开始请求binlog这个位置包含文件名和日志偏移量
2.在备库B上执行start slave命令这时备库会启动两个线程io_thread和sql_thread。其中io_thread负责与主库建立连接
3.主库A校验完用户名、密码后开始按照备库B传过来的位置从本地读取binlog发给B
4.备库B拿到binlog后写到本地文件称为中转日志
5.sql_thread读取中转日志解析出日志里的命令并执行
由于多线程复制方案的引入sql_thread演化成了多个线程

View file

@ -0,0 +1,45 @@
#### 背景说明如下
为了安全mysql数据库安装在内网环境外网无法直连只能通过与数据库在同一个内网的、可以与外网通信的服务器连接即使用ssh隧道连接。
一般的第三方可视化客户端连接工具都可以配置ssh隧道。若使用命令行连接就需要使用命令建立隧道。
##### 建立隧道命令如下:
```
# 需要连接数据库的外网环境,执行下列命令
ssh -p {ssh_port} -i {rsa_file} -fNL {local_port}:{mysql_ip}:{mysql_port} {ssh_user}@{ssh_ip}
```
###### 命令详解:
* -p {ssh_port}: 指定跳板机器的ssh服务的端口也就是B服务器
* -i {rsa_file}:指定连接跳板机的ssh公钥由跳板机的ssh服务端生成如果不指定公钥或者公钥验证失败则会弹出密码进行登录。如果需要密码登录可以不填-i
* -f:告诉SSH客户端在后台运行也就是执行命令之后在进程监听需要关闭直接kill
* -N:只进行端口转发,不执行命令
* -L:指定连接服务的格式 [bind_address:]port:host:hostport
* {local_port}:本地监听的端口
* {mysql_ip}转发到的mysql的ip或域名远程mysql主机地址
* {mysql_port}转发到的mysql的端口
* {ssh_port}:跳板机的
* {ssh_user}跳板机的ssh用户名(如果为rsa登录则ras对应的用户名和ssh_user一致)
* {ssh_ip}跳板机的ip或域名
##### 连接数据库命令:
```
mysql -h127.0.0.1 -P {local_port} -u{mysql_user} -p
```
#### 举例说明
A需要连接数据库的外网服务器centos 8
B只有内网地址或只能被特定主机连接的数据库服务器。数据库连接为172.16.0.35:3306
C可以被A直连与B在同一个内网中/或可以连接B。公网地址为3.3.3.3连接公钥为rsa_pub.pem
###### 1、建立隧道
*A执行*
```
ssh -p 22 -i rsa_pub.pem -fNL 3320:172.16.0.35:3306 root@3.3.3.3
```
###### 2、查看本地监听端口
```
ss -anltp | grep 3320
```
###### 3、连接数据库
```
mysql -h 127.0.0.1 -P 3320 -u admin -p
```

View file

@ -0,0 +1,8 @@
#### 异步复制Asynchronous replication
MySQL默认的复制即是异步的主库在执行完客户端提交的事务后会立即将结果返给给客户端并不关心从库是否已经接收并处理这样就会有一个问题主如果crash掉了此时主上已经提交的事务可能并没有传到从上如果此时强行将从提升为主可能导致新主上的数据不完整。
#### 全同步复制Fully synchronous replication
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
#### 半同步复制Semisynchronous replication
介于异步复制和全同步复制之间主库在执行完客户端提交的事务后不是立刻返回给客户端而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制半同步复制提高了数据的安全性同时它也造成了一定程度的延迟这个延迟最少是一个TCP/IP往返的时间。所以半同步复制最好在低延时的网络中使用。

View file

@ -0,0 +1,31 @@
要求:
1、主从mysql版本要一致
2、若版本不一致主版本要低于从
3、从头开始或主服务器数据备份从服务器恢复数据并从主备份所在位置进行服务
注意(都需要启动):
1、时间需要同步
2、配置文件
my.cnf
修改二进制日志存放位置安全log-bin=目录/文件
修改二进制文件的格式为binlog_format=mixed
修改服务id server-id=1
my.cnf
要从主服务器复制二进制日志所以从的二进制文件要关闭log-bin=OFF或注释掉
修改服务id与主服务器不同如 server-id=11
添加复制日志relay-log=目录/文件
只读read-only=on(仅限制不具备super权限用户无法执行的写操作)
3、主从复制的事务安全
在主服务器上配置sync_binlog=1(事务提交即同步)
1、主服务器执行创建一个有复制权限的用户并授权
grant replication slave, replication client on *.* to 'rep'@'从ip地址' identified by 'reppass';
flush plivileges;
2、备份主服务器上数据需要包含position信息在导出的数据文件头部
备份InnoDB存储引擎的数据库mysqldump --all-database --single-transaction -flush-logs --master-data=2 > 数据文件
备份MyISAM存储引擎的数据库mysqldump --all-database --lock-all-tables -flush-logs --master-data=2 > 数据文件
3、从服务器执行连接主服务器
change master to MASTER_HOST='主服务器ip' MASTER_USER='主服务器用户' MASTER_PASSWORD='密码' MASTER_PORT='端口' MASTER_LOG_FILE='主服务器二进制文件' MASTER_LOG_POS=从主服务器二进制文件位置读取
4、从服务器启动slave执行
start slave

View file

@ -0,0 +1,3 @@
索引是帮助数据库高效获取数据的*排好序*的*数据结构*
聚簇索引(聚集索引),索引与数据放在一起,索引结构的叶子节点保存了行数据
非聚簇索引,索引与数据不放在一起,索引结构的叶子节点指向了数据对应的位置

7
数据库/mysql/锁.md Normal file
View file

@ -0,0 +1,7 @@
*读锁* 也叫共享锁、S锁若事务T对数据对象A加上S锁则事务T可以读A但不能修改A其他事务只能再对A加S锁而不能加X锁直到T释放A上的S 锁。这保证了其他事务可以读A但在T释放A上的S锁之前不能对A做任何修改。
*写锁* 又称排他锁、X锁。若事务T对数据对象A加上X锁事务T可以读A也可以修改A其他事务不能再对A加任何锁直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
*表锁* 操作对象是数据表。Mysql大多数锁策略都支持是系统开销最低但并发性最低的一个锁策略。事务t对整个表加读锁则其他事务可读不可写若加写锁则其他事务增删改都不行。
*行级锁* 操作对象是数据表中的一行。是MVCC技术用的比较多的。行级锁对系统开销较大但处理高并发较好。

View file

@ -0,0 +1,28 @@
<<<<<<< HEAD
创建数据库文件
CREATE TABLESPACE insurance LOGGING DATAFILE '/data/database/orcl/insurance.dbf' SIZE 100M AUTOEXTEND ON NEXT 32M MAXSIZE 500M EXTENT MANAGEMENT LOCAL;
创建数据库临时文件
create temporary TABLESPACE insurance_temp tempfile '/data/database/orcl/insurance_temp.dbf' SIZE 100M AUTOEXTEND ON NEXT 32M MAXSIZE 500M EXTENT MANAGEMENT LOCAL;
创建用户与上述两个文件形成映射关系
CREATE USER insurance IDENTIFIED BY "Insur@nce#20" DEFAULT TABLESPACE insurance TEMPORARY TABLESPACE insurance_temp;
添加用户权限
grant connect,resource,dba to insurance;
=======
创建数据库文件
CREATE TABLESPACE insurance LOGGING DATAFILE '/data/database/orcl/insurance.dbf' SIZE 100M AUTOEXTEND ON NEXT 32M MAXSIZE 500M EXTENT MANAGEMENT LOCAL;
创建数据库临时文件
create temporary TABLESPACE insurance_temp tempfile '/data/database/orcl/insurance_temp.dbf' SIZE 100M AUTOEXTEND ON NEXT 32M MAXSIZE 500M EXTENT MANAGEMENT LOCAL;
创建用户与上述两个文件形成映射关系
CREATE USER insurance IDENTIFIED BY "Insur@nce#20" DEFAULT TABLESPACE insurance TEMPORARY TABLESPACE insurance_temp;
添加用户权限
grant connect,resource,dba to insurance;
>>>>>>> 28bec05... 20200611
grant create session to insurance;

View file

@ -0,0 +1,57 @@
1.进入到sqlplus启动实例
[oracle@redhat ~]$ su - oracle --“切换到oracle用户”
Password:
[oracle@redhat ~]$ lsnrctl start --“打开监听”
LSNRCTL for Linux: Version 10.2.0.1.0 - Production on 14-OCT-2009 19:06:40
Copyright (c) 1991, 2005, Oracle. All rights reserved.
Starting /home/oracle/product/10g/bin/tnslsnr: please wait...
TNSLSNR for Linux: Version 10.2.0.1.0 - Production
System parameter file is /home/oracle/product/10g/network/admin/listener.ora
Log messages written to /home/oracle/product/10g/network/log/listener.log
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC2)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=redhat)(PORT=1522)))
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC2)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 10.2.0.1.0 - Production
Start Date 14-OCT-2009 19:06:40
Uptime 0 days 0 hr. 0 min. 0 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /home/oracle/product/10g/network/admin/listener.ora
Listener Log File /home/oracle/product/10g/network/log/listener.log
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC2)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=redhat)(PORT=1522)))
Services Summary...
Service "PLSExtProc" has 1 instance(s).
Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully
[oracle@redhat ~]$ sqlplus /nolog --“进入到sqlplus”
SQL*Plus: Release 10.2.0.1.0 - Production on Wed Oct 14 19:06:45 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
SQL> conn /as sysdba --“连接到sysdba”
Connected to an idle instance.
SQL> startup --“启动数据库实例”
ORACLE instance started.
Total System Global Area 285212672 bytes
Fixed Size 1218968 bytes
Variable Size 88082024 bytes
Database Buffers 188743680 bytes
Redo Buffers 7168000 bytes
Database mounted.
Database opened.
SQL> shutdown immediate --“关闭数据库实例”
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> exit
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
[oracle@redhat ~]$ lsnrctl stop --“关闭监听”
LSNRCTL for Linux: Version 10.2.0.1.0 - Production on 14-OCT-2009 19:08:06
Copyright (c) 1991, 2005, Oracle. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC2)))
The command completed successfully

View file

@ -0,0 +1,12 @@
### 添加select权限
```
grant select on USER1.TABLE to USER2;
```
### 添加创建同义词权限
```
grant create synonym to USER2;
```
### 创建同义词
```
create or replace synonym TABLE for USER1.TABLE;
```

View file

@ -0,0 +1 @@
exp user/pwd@dbname file=d:text.dmp owner=(user)

View file

@ -0,0 +1,86 @@
```sql
# 查询表空间
SELECT TABLESPACE_NAME "表空间",
To_char(Round(BYTES / 1024, 2), '99990.00')
|| '' "实有",
To_char(Round(FREE / 1024, 2), '99990.00')
|| 'G' "现有",
To_char(Round(( BYTES - FREE ) / 1024, 2), '99990.00')
|| 'G' "使用",
To_char(Round(10000 * USED / BYTES) / 100, '99990.00')
|| '%' "比例"
FROM (SELECT A.TABLESPACE_NAME TABLESPACE_NAME,
Floor(A.BYTES / ( 1024 * 1024 )) BYTES,
Floor(B.FREE / ( 1024 * 1024 )) FREE,
Floor(( A.BYTES - B.FREE ) / ( 1024 * 1024 )) USED
FROM (SELECT TABLESPACE_NAME TABLESPACE_NAME,
Sum(BYTES) BYTES
FROM DBA_DATA_FILES
GROUP BY TABLESPACE_NAME) A,
(SELECT TABLESPACE_NAME TABLESPACE_NAME,
Sum(BYTES) FREE
FROM DBA_FREE_SPACE
GROUP BY TABLESPACE_NAME) B
WHERE A.TABLESPACE_NAME = B.TABLESPACE_NAME)
--WHERE TABLESPACE_NAME LIKE 'CDR%' --这一句用于指定表空间名称
ORDER BY Floor(10000 * USED / BYTES) DESC;
```
```
set linesize 140 pagesize 10000
col "Status" for a10
col "Name" for a25
col "Type" for a10
col "Extent" for a15
col "Size(M)" for a15
col "Used(M)" for a15
col "Used(%)" for a20
col "Maxused(%)" for a20
SELECT d.status "Status", d.tablespace_name "Name", d.contents "Type", d.extent_management "Extent",
TO_CHAR(NVL(a.bytes / 1024 / 1024, 0),'99,999,990') "Size(M)",
TO_CHAR(NVL(a.bytes - NVL(f.bytes, 0), 0)/1024/1024,'999,999,999') "Used(M)",
TO_CHAR(NVL((a.bytes - NVL(f.bytes, 0)) / a.bytes * 100, 0), '900.00') "Used(%)",
TO_CHAR(100-((a.maxbytes - a.bytes + f.bytes) / a.maxbytes * 100), '900.00') "Maxused(%)"
FROM sys.dba_tablespaces d,
(select tablespace_name, sum(bytes) bytes,sum(decode(autoextensible, 'YES',maxbytes,'NO', bytes)) maxbytes from dba_data_files group by tablespace_name) a,
(select tablespace_name, sum(bytes) bytes from dba_free_space group by tablespace_name) f
WHERE d.tablespace_name = a.tablespace_name(+) AND d.tablespace_name = f.tablespace_name(+) AND NOT
(d.extent_management like 'LOCAL' AND d.contents like 'TEMPORARY')
UNION ALL
SELECT d.status "Status", d.tablespace_name "Name", d.contents "Type", d.extent_management "Extent",
TO_CHAR(NVL(a.bytes / 1024 / 1024, 0),'99,999,999') "Size(M)",
TO_CHAR(NVL(t.bytes,0)/1024/1024,'999,999,999') "Used(M)",
TO_CHAR(NVL(t.bytes / a.bytes * 100, 0), '990.00') "Used(%)" ,
TO_CHAR(NVL(t.bytes / a.maxbytes * 100, 0), '990.00') "Maxused(%)"
FROM sys.dba_tablespaces d,
(select tablespace_name, sum(bytes) bytes,sum(decode(autoextensible, 'YES',maxbytes,'NO', bytes)) maxbytes from dba_temp_files group by tablespace_name) a,
(select tablespace_name, sum(bytes_cached) bytes from v$temp_extent_pool group by tablespace_name) t
WHERE d.tablespace_name = a.tablespace_name(+) AND d.tablespace_name = t.tablespace_name(+) AND
d.extent_management like 'LOCAL' AND d.contents like 'TEMPORARY'
ORDER BY 7;
```
```sql
# 查询表空间文件及目录
select
b.file_name 物理文件名,
b.tablespace_name 表空间,
b.bytes/1024/1024 大小M,
(b.bytes-sum(nvl(a.bytes,0)))/1024/1024 已使用M,
substr((b.bytes-sum(nvl(a.bytes,0)))/(b.bytes)*100,1,5) 利用率
from dba_free_space a,dba_data_files b
where a.file_id=b.file_id
group by b.tablespace_name,b.file_name,b.bytes
order by b.tablespace_name;
```
```
select tablespace_name,file_id,bytes/1024/1024,file_name from dba_data_files order by file_id;
```
```sql
# 增加表空间文件
ALTER TABLESPACE [表空间名称] ADD DATAFILE '数据文件路径' SIZE 8G;
```
```sql
# 查询归档日志空间使用情况
select to_char(next_time, 'yyyy-mm-dd') hourtime, round(sum(blocks * block_size) / 1024 / 1024 / 1024) archlog_GB from v$archived_log where dest_id = 1 and next_time > sysdate - 15 group by to_char(next_time, 'yyyy-mm-dd') order by to_char(next_time, 'yyyy-mm-dd');
```

View file

@ -0,0 +1,12 @@
## 查询被锁定的表
```
select b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_object a,dba_objects b where b.object_id = a.object_id;
```
## 查询发生锁定表的会话及序列号
```
select b.username,b.sid,b.serial#,logon_time from v$locked_object a,v$session b where a.session_id = b.sid order by b.logon_time;
```
## 结束产生锁表的会话
```
alter system kill session 'SID,SERIAL#';
```

View file

@ -0,0 +1,21 @@
## 查询表所属用户
```
SELECT * FROM DBA_TABLES WHERE TABLE_NAME='表名';
```
```
SELECT * FROM ALL_OBJECTS WHERE OBJECT_TYPE='TABLE' and OBJECT_NAME='表名'
```
```
select owner from dba_tables where table_name=upper('表名');
```
## 查询视图所属用户
```
SELECT * FROM ALL_VIEWS WHERE VIEW_NAME='视图名';
```
```
SELECT * FROM ALL_OBJECTS WHERE OBJECT_TYPE='VIEW' and OBJECT_NAME='视图名'
```
## 查询存储过程所属用户
```
SELECT * FROM ALL_OBJECTS WHERE OBJECT_TYPE='PROCEDURE' and OBJECT_NAME='存储过程名'
```

View file

@ -0,0 +1,25 @@
#!/bin/bash
# Edit 2020/04/16
# sql script
# https://blog.csdn.net/Hehuyi_In/article/details/95893869
# example
# sql="select count(*) from pg_stat_activity where state='idle in transaction';"
# message="处于空闲状态的会话"
sql=""
message=""
user=postgres
source /home/$user/.bash_profile
if [ $UID -ne `id -u $user` ];then
echo -e "\033[31;1mNot Manager of PostgreSQL! \033[0m"
exit 1
fi
# get value
valuse=`psql postgres -c "$sql" | sed -n '3p' | sed 's/ //g'`
echo "$message=$valuse"

View file

@ -0,0 +1,27 @@
#!/bin/bash
# Edit 2020/4/10
backup=$PGDATA/../backup
now=`date +%Y%m%d-%H%M%S`
aweekago=`date -d -7days +%Y%m%d`
host=10.1.139.126
port=5432
username=yanzhao
database=yzdb
if [ $UID -eq 0 ];then
echo -e "\033[31m;1mDo not Use Root! \033[0m"
exit 1
fi
source ~/.bash_profile
if [ ! -f $backup ];then
mkdir -p $backup
fi
pg_dump -h $host -p $port -U $username --no-password -d $database -F c -b -v -f $backup/$database-$now.bak
cd $backup && tar zcvf $database-$aweekago.tar.gz $database-$aweekago-* --remove-files

View file

@ -0,0 +1,34 @@
#!/bin/bash
# Edit 2020/04/15
user=postgres
source /home/$user/.bash_profile
backup=$PGDATA/../backup
today=`date +%F`
aweekago=`date -d -7days +%F`
host=10.1.139.126
port=5432
username=rep
if [ $UID -ne `id -u $user` ];then
echo -e "\033[31;1mNot Manager of PostgreSQL! \033[0m"
exit 1
fi
# create base backup
echo -e "\033[33;1m---$today---\nBack up Now!\n---\033[0m"
if [ -f "$backup/$today/base" ];then
mkdir -p $backup/$today/base
fi
pg_basebackup -D $backup/$today/base -h $host -p $port -Ft -z -P -v -w -U $username
echo -e "\033[33;1m---\n---Finish---\033[0m"
# switch wal
psql postgres -c "checkpoint;"
psql postgres -c "select pg_switch_wal();"
# clean backup 7 days ago
rm -rf $backup/$aweekago

Binary file not shown.

View file

@ -0,0 +1 @@
alter user rep with password 'yanzhao';

View file

@ -0,0 +1 @@
CREATE DATABASE exampledb OWNER dbuser;

View file

@ -0,0 +1,11 @@
创建quartztstopr用户并赋权限
1、创建用户create role 与create user 区别只有create user默认加上login而create role不加
postgres=# create user quartztstopr with password 'Quartztstopr@2018';
2、切换到quartztst数据库
postgres=# \c quartztst
3、为用户赋增删改查权限
quartztst=# grant select,update,delete,insert on all tables in schema public to quartztstopr; # 查询,删除,更新,插入
quartztst=# grant all privileges on all tables in schema public to quartztstopr; # 所有权限
4、为用户赋修改表字段权限
quartztst=# grant all privileges on all tables in schema public to quartztstopr;

View file

@ -0,0 +1,45 @@
1、导入整个数据库
# psql -U postgres(用户名) 数据库名(缺省时同用户名) < /data/dum.sql
2、导出整个数据库
# pg_dump -h localhost -U postgres(用户名) 数据库名(缺省时同用户名) >/data/dum.sql
3、导出某个表
# pg_dump -h localhost -U postgres(用户名) 数据库名(缺省时同用户名) -t table(表名) >/data/dum.sql
4、压缩方法
一般用dump导出数据会比较大推荐使用xz压缩
压缩方法 xz dum.sql 会生成 dum.sql.xz 的文件
5、xz压缩数据倒数数据库方法
xzcat /data/dum.sql.xz | psql -h localhost -U postgres(用户名) 数据库名(缺省时同用户名)
pg_dump -F c -f  /dbbak/pgdumpbak/c.dmp  -C -E  UTF8 -h 127.0.0.1 -U postgres testdb     #二进制格式备份文件
 
pg_dump -F p -f  /dbbak/pgdumpbak/p.dmp  -C -E  UTF8 -h 127.0.0.1 -U postgres testdb  #文本格式备份文件,”-C” 表示包含创建语句
n
pg_restore /dbbak/c.dmp|less    可以解析二进制格式的备份文件
pg_restore -l /dbbak/c.dmp   
pg_restore -d testdb /dbbak/pgdumpbak/c.dmp   #需要先创建目标库
pg_restore -d postgres /dbbak/pgdumpbak/p.dmp  #文件中包含创建数据库的命令,不需要创建目标库

View file

@ -0,0 +1,7 @@
DO $$DECLARE r record;
BEGIN
FOR r IN SELECT tablename/viewname FROM pg_tables/pg_views WHERE schemaname = 'public'
LOOP
EXECUTE 'alter table '|| r.tablename/r.viewname ||' owner to new_owner;';
END LOOP;
END$$;

View file

@ -0,0 +1,9 @@
查询所有库名
\l
SELECT datname FROM pg_database;
查询当前库下有哪些表
\dt
或者
SELECT tablename FROM pg_tables;

View file

@ -0,0 +1,6 @@
查询cardbtstopr的权限
1、切换到cardbtst数据库
postgres=# \c cardbtst
2、查询权限
cardbtst=# select * from information_schema.role_table_grants where grantee='cardbtstopr';

View file

@ -0,0 +1,356 @@
在postgresql中database,schema,table之间关系
从逻辑上看schema、table都是位于database之下。在postgres数据库下建立表(相当于建立在public schema下)理解pg下的权限
\dp - lists table/view permissions
\dn+ - lists schema permissions
\l+ does not list all users that can access the database
using psql from postgres 8.4 and postgres 9.0, and the command \l or \l+ gives me column Access Privileges where I have entry:
<user_name>=c/<database_name>
\dp显示的项解释如下
角色名=xxxx -- 被授予给一个角色的特权
=xxxx -- 被授予给 PUBLIC 的特权
r -- SELECT ("读")
w -- UPDATE ("写")
a -- INSERT ("追加")
d -- DELETE
D -- TRUNCATE
x -- REFERENCES
t -- TRIGGER
X -- EXECUTE
U -- USAGE
C -- CREATE
c -- CONNECT
T -- TEMPORARY
arwdDxt -- ALL PRIVILEGES (对于表,对其他对象会变化)
* -- 用于前述特权的授权选项
/yyyy -- 授予该特权的角色
在PostgreSQL中可以把角色划分为如下几类
SELECT该权限用来查询表或是表上的某些列或是视图序列。
INSERT该权限允许对表或是视图进行插入数据操作也可以使用COPY FROM进行数据的插入。
UPDATE该权限允许对表或是或是表上特定的列或是视图进行更新操作。
DELETE该权限允许对表或是视图进行删除数据的操作。
TRUNCATE允许对表进行清空操作。
REFERENCES允许给参照列和被参照列上创建外键约束。
TRIGGER允许在表上创建触发器。
CREATE对于数据库允许在数据库上创建Schema对于Schema允许对Schema上创建数据库对象对于表空间允许把表或是索引指定到对应的表空间上。
CONNECT允许用户连接到指定的数据库上。
TEMPORARY或是TEMP允许在指定数据库的时候创建临时表。
EXECUTE允许执行某个函数。
USAGE对于程序语言来说允许使用指定的程序语言创建函数对于Schema来说允许查找该Schema下的对象对于序列来说允许使用currval和nextval函数对于外部封装器来说允许使用外部封装器来创建外部服务器对于外部服务器来说允许创建外部表。
ALL PRIVILEGES表示一次性给予可以授予的权限。
创建两个测试账号
create role web login connection limit 9 password 'web_app';
create role mobile login connection limit 9 password 'mob_ile';
ALTER DEFAULT PRIVILEGES IN SCHEMA dba GRANT SELECT ON TABLES TO mobile;
没有起到作用,用下面的语句:
GRANT SELECT ON ALL TABLES IN SCHEMA dba TO mobile;
从dba终端看是有权限的但mobile中用\dpp却看不到难道要重新登录一下
重新登录后也看不到,试试下面的规则:
GRANT CONNECT ON DATABASE dba TO mobile;
GRANT USAGE ON SCHEMA dba TO mobile;
GRANT SELECT ON ALL TABLES IN SCHEMA dba TO mobile;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA dba to mobile;
单表授权
GRANT SELECT,INSERT,UPDATE ON TABLE web9 TO web;
成功。
后来发现是search_path这个变量的问题在当前的变量中没有包含dba所以\dpp时看不见但从其中的表中取数据是可以的select * from dba.table limit 9;
If your read-only user doesn't have permission to list tables (i.e. \d returns no results), it's probably because you don't have USAGE permissions for the schema. USAGE is a permission that allows users to actually use the permissions they have been assigned. What's the point of this? I'm not sure. To fix:
# You can either grant USAGE to everyone
GRANT USAGE ON SCHEMA public TO public;
# Or grant it just to your read only user
GRANT USAGE ON SCHEMA public TO readonlyuser;
授权首先要能连接(connection)到数据库(pg_hba.conf)上,在模式上要有使用权限(usage),然后是其下的对象的操作权限(如果该对象可以再度分割,如表中有列,对列赋予不同的权限);可以对用户在给定的模式下设定权限(可批可零),或对给定的模式中指定默认的操作权限(批量)。
撤销权限
REVOKE CREATE ON SCHEMA public FROM public;
第一个 "public" 是模式,第二个 "public" 意思是"所有用户"。
GRANT SELECT ON ALL TABLES IN SCHEMA PUBLIC to freeoa_role; --赋予freeoa_role所有表的SELECT权限
特殊符号ALL代表所访问权限PUBLIC代表所有用户。
要把新的模式放到路径中来,我们用:
SET search_path TO myschema,"$user",public;
仅对本次会话有效,下次登录又要设置一下。
或者修改用户的搜索路径,这样即使下次登录也不用重新设置:
ALTER USER mobile SET search_path=dba, "$user",public;
修改模式默认的权限
alter default privileges in schema public grant select on tables to web;
比较通用的模式下对象授权方式多采用:先移除所有用户的所有权限,再有针对性的授权。
REVOKE ALL ON ALL TABLES IN SCHEMA public FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO user_name;
或者修改具体用户的默认权限
ALTER DEFAULT PRIVILEGES
FOR ROLE some_role -- Alternatively "FOR USER"
IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO user_name;
这是一个很开放的权限
grant all privileges on database dbname to dbuser;
grant是赋予用户schema下当前表的权限alter default privileges是赋予用户schema下表的默认权限这样以后新建表就不用再赋权限了。当我们创建只读账号的时候需要执行grant和alter default privileges。其次这样可很好地解决每次新建表就要赋一次权限的问题了。
alter default privileges in schema dba grant select,insert,update,delete on tables to mobile;
创建的普通用户默认是没有任何权限的。查看表等对象的权限可通过:\dpp来查看相当直观。
序列的权限与解决办法
在insert的时候指定列插入主键id是serial类型会默认走sequence的下一个值但前面只赋予了表的权限所以会出现下面的问题
postgres=> insert into t4 ( name ) values ( 'aa' );
ERROR: permission denied for sequence t4_id_seq
解决方法就是再赋一次sequence的值就行了
alter default privileges in schema public grant usage on sequences to user2;
删除用户
删除用户和组
删除用户和组很简单:
DROP ROLE role_name;
DROP ROLE IF EXISTS role_name;
删除组role只会删除组的role本身组的成员并不会被删除。
postgres=> \c - postgres
You are now connected to database "postgres" as user "postgres".
postgres=# drop role user2;
ERROR: role "user2" cannot be dropped because some objects depend on it
DETAIL: privileges for table t5
privileges for sequence t5_id_seq
privileges for default privileges on new sequences belonging to role postgres in schema public
privileges for table t4
privileges for default privileges on new relations belonging to role postgres in schema public
当我们删除用户的时候,会提示有权限依赖,所以我们要删除这些权限
postgres=# alter default privileges in schema public revoke usage on sequences from user2;
ALTER DEFAULT PRIVILEGES
postgres=# alter default privileges in schema public revoke select,insert,delete,update on tables from user2;
ALTER DEFAULT PRIVILEGES
postgres=# revoke select,insert,delete,update on all tables in schema public from user2;
REVOKE
postgres=# revoke usage on all sequences in schema public from user2;
REVOKE
postgres=# drop role user2;
DROP ROLE
Pg权限分为两部分一部分是“系统权限”或者数据库用户的属性可以授予role或user(两者区别在于login权限)一部分为数据库对象上的操作权限。对超级用户不做权限检查其它走acl。对于数据库对象开始只有所有者和超级用户可以做任何操作其它走acl。在pg里对acl模型做了简化组和角色都是role。数据库对象上的权限有SELECTINSERTUPDATEDELETERULEREFERENCESTRIGGERCREATETEMPORARYEXECUTE 和 USAGE等。
可以用特殊的名字 PUBLIC 把对象的权限赋予系统中的所有角色。 在权限声明的位置上写 ALL表示把适用于该对象的所有权限都赋予目标角色。
视图 pg_roles提供访问数据库角色有关信息的接口。 它只是一个 pg_authid 表的公开可读部分的视图,把口令字段用空白填充了。
pg_roles字段
名字
类型
引用
描述
rolname
name
角色名
rolsuper
bool
有超级用户权限的角色
rolcreaterole
bool
可以创建更多角色的角色
rolcreatedb
bool
可以创建数据库的角色
rolcatupdate
bool
可以直接更新系统表的角色。(除非这个字段为真,否则超级用户也不能干这个事情。)
rolcanlogin
bool
可以登录的角色,也就是说,这个角色可以给予初始化会话认证的标识符。
rolpassword
text
不是口令(总是 ********
rolvaliduntil
timestamptz
口令失效日期(只用于口令认证);如果没有失效期,为 NULL
rolconfig
text[]
运行时配置变量的会话缺省
角色属性(Role Attributes)
一个数据库角色可以有一系列属性,这些属性定义了他的权限。
属性 说明
login 只有具有 LOGIN 属性的角色可以用做数据库连接的初始角色名。
superuser 数据库超级用户
createdb 创建数据库权限
createrole 允许其创建或删除其他普通的用户角色(超级用户除外)
replication 做流复制的时候用到的一个用户属性,一般单独设定。
password 在登录时要求指定密码时才会起作用比如md5或者password模式跟客户端的连接认证方式有关
inherit 用户组对组员的一个继承标志,成员可以继承用户组的权限特性
在psql中的查看权限的快捷指令
\dn[S+] [PATTERN] 列出所有模式
\dp [模式] 列出表,视图和序列的访问权限,同\z
\du[S+] [PATTERN] 列出角色
\ddp [模式] 列出默认权限
\drds [模式1 [模式2]] 列出每个数据库的角色设置
database、schema、table_seq_view_etc、table_column 分4个级别来授权。
查看pg_hba.conf 文件在角色属性中关于password的说明在登录时要求指定密码时才会起作用比如md5或者password模式跟客户端的连接认证方式有关。
给已存在用户赋权限
使用ALTER ROLE 命令。
ALTER ROLE name RENAME TO new_name
ALTER ROLE name [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT }
ALTER ROLE name [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT
ALTER ROLE name [ IN DATABASE database_name ] RESET configuration_parameter
ALTER ROLE name [ IN DATABASE database_name ] RESET ALL
为角色成员赋权
查看角色信息
psql 终端可以用\du 或\du+ 查看,也可以查看系统表
select * from pg_roles;
select * from pg_user;
在系统的角色管理中通常会把多个角色赋予一个组这样在设置权限时只需给该组设置即可撤销权限时也是从该组撤销。在PostgreSQL中首先需要创建一个代表组的角色之后再将该角色的membership 权限赋给独立的角色即可。
创建组角色
# CREATE ROLE father login nosuperuser nocreatedb nocreaterole noinherit encrypted password 'freeoa';
给father 角色赋予数据库test 连接权限和相关表的查询权限。
# GRANT CONNECT ON DATABASE test to father;
test=> GRANT USAGE ON SCHEMA public to father;
WARNING: no privileges were granted for "public"
test=> GRANT SELECT on public.emp to father;
创建成员角色
test=> \c postgres postgres
You are now connected to database "postgres" as user "postgres".
# CREATE ROLE son1 login nosuperuser nocreatedb nocreaterole inherit encrypted password 'freeoa.net';
这里创建了son1 角色并开启inherit 属性。PostgreSQL 里的角色赋权是通过角色继承(INHERIT)的方式实现的。
将father 角色赋给son1
# GRANT father to son1;
还有另一种方法,就是在创建用户的时候赋予角色权限。
# CREATE ROLE son2 login nosuperuser nocreatedb nocreaterole inherit encrypted password 'freeoa.net' in role father;
用户在public模式下创建的表对于其它用户能看到但查不了会报"对关系 prv 权限不够",除非你是这个库的属主。
可以通过函数来验证模式下的表的相应权限:
select has_table_privilege('public.table1','select');
select has_table_privilege('dba.webcon_cid_seq','update');
对sequence类型的授权
select 什么都做不了usage有currval,nextval这两个函数可用setval不可用要使用setval就必须有update权限。
grant usage on sequence web_cid_seq to some_user;
切换ROLE
SET ROLE role_name; --切换到role_name用户
RESET ROLE; --切换回最初的role
INHERIT权限该属性使组成员拥有组的所有权限
ALTER ROLE freeoa_user INHERIT;
通过以下方式禁止用户登录
ALTER ROLE username WITH NOLOGIN;
第三方的小工具
somebody created a convenient script for that; pg_grant_read_to_db.sh. This script grants read-only privileges to a specified role on all tables, views and sequences in a database schema and sets them as default.
url:https://gist.github.com/jirutka/afa3ce62b1430abf7572
参考来源
GRANT[http://postgres.cn/docs/9.5/sql-grant.html]
ALTER DEFAULT PRIVILEGES[http://postgres.cn/docs/9.5/sql-alterdefaultprivileges.html]

View file

@ -0,0 +1,310 @@
一.USER用户管理
1.查看用户
pg中的role,user,group基本是一样的,只是默认创建的role,group没有登录数据库的权限.用户分为普通用户和超级用户
1.使用\du查看数据库中的用户,其中role name是用户名,第二列是用户的属性,第三列表示用户具有哪些成员,例如将suq赋予给brent
postgres=# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
brent | | {suq}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
suq | 1 connection | {}
zdry | Superuser +| {}
| Password valid until infinity |
2.创建用户
1.查看创建用户的语法
test=# \h create user
Command: CREATE USER
Description: define a new database role
Syntax:
CREATE USER name [ [ WITH ] option [ ... ] ]
where option can be:
SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| INHERIT | NOINHERIT --继承
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit
| [ ENCRYPTED ] PASSWORD 'password'
| VALID UNTIL 'timestamp'
| IN ROLE role_name [, ...]
| IN GROUP role_name [, ...]
| ROLE role_name [, ...]
| ADMIN role_name [, ...]
| USER role_name [, ...]
| SYSID uid
2.创建一个普通用户
postgres=# create user test ENCRYPTED password 'test';
CREATE ROLE
3.为创建一个超级用户
test=# create user dsg superuser;
CREATE ROLE
4.创建一个普通用户,并且赋予相关权限
test=# create user dsg createdb createrole inherit password 'dsg';
CREATE ROLE
3.修改用户
1.查看修改用户语句
test=# \h alter user
Command: ALTER USER
Description: change a database role
Syntax:
ALTER USER role_specification [ WITH ] option [ ... ]
where option can be:
SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit
| [ ENCRYPTED ] PASSWORD 'password'
| VALID UNTIL 'timestamp'
ALTER USER name RENAME TO new_name
ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT }
ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT
ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] RESET configuration_parameter
ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] RESET ALL
where role_specification can be:
role_name
| CURRENT_USER
| SESSION_USER
2.修改用户为超级用户
postgres=# alter user test superuser;
ALTER ROLE
3.将超级用户修改为普通用户
postgres=# alter user test nosuperuser;
ALTER ROLE
4.修改用户密码
test=# alter user dsg password 'test';
ALTER ROLE
5.修改用户名
test=# alter user dsg rename to dds;
NOTICE: MD5 password cleared because of role rename
ALTER ROLE
6.锁定/解锁用户,不允许/允许其登录
test=# alter user test nologin;
ALTER ROLE
test=# alter user test login;
ALTER ROLE
7.设置用户的连接数,其中0表示不允许登录,-1表示无限制
test=# alter user test connection limit 10;
ALTER ROLE
4.删除用户
1.直接删除用户
test=# drop user dds;
DROP ROLE
如果用户在数据库中有相关对象,不能直接删除,需要将相关对象所属修改到其它用户中
test=# drop user dsg;
ERROR: role "dsg" cannot be dropped because some objects depend on it
DETAIL: owner of table zzz.kkk
privileges for schema zzz
将dsg的所属用户修改为test:
test=# reassign owned by dsg to test;
REASSIGN OWNED
还需要把权限进行收回,再进行删除:
test=# revoke all on schema zzz from dsg;
REVOKE
test=# drop user dsg;
DROP ROLE
二.schema模式管理
首先介绍一下postgresql中的schema,postgresql中的schema和其它关系型数据库中的schema含义是一致的,在oracle中叫schema或者用户,只是oracle中schema和用户是始终一一对应.
在mysql中database和schema是一一对应的.postgresql中user和schema是可以不一致的,相对比其它数据库复杂一点.
在创建schema的时候,可以指定schema的所属用户,默认的只有所属用户和超级用户才能在此schema进行对象操作,否则就需要授权.
1.使用\dn查看数据库的schema
test=# \dn
List of schemas
Name | Owner
--------+----------
brent | brent
public | postgres
suq | suq
zzz | test
(4 rows)
2.创建schema
1.查看创建schema语法
test=# \h create schema
Command: CREATE SCHEMA
Description: define a new schema
Syntax:
CREATE SCHEMA schema_name [ AUTHORIZATION role_specification ] [ schema_element [ ... ] ]
CREATE SCHEMA AUTHORIZATION role_specification [ schema_element [ ... ] ]
CREATE SCHEMA IF NOT EXISTS schema_name [ AUTHORIZATION role_specification ]
CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_specification
where role_specification can be:
user_name
| CURRENT_USER
| SESSION_USER
2.创建一个schema,并且设置所属用户为test:
test=# create schema zzz authorization test;
CREATE SCHEMA
3.删除schema
1.删除schema,如果schema中存在对象,则需要使用cascade选项:
test=# drop schema zzz;
ERROR: cannot drop schema zzz because other objects depend on it
DETAIL: table zzz.test depends on schema zzz
HINT: Use DROP ... CASCADE to drop the dependent objects too.
test=# drop schema zzz cascade;
NOTICE: drop cascades to table zzz.test
DROP SCHEMA
三.权限管理
postgresql中的权限可以大概分为以下几种:
SELECT该权限用来查询表或是表上的某些列或是视图序列。
INSERT该权限允许对表或是视图进行插入数据操作也可以使用COPY FROM进行数据的插入。
UPDATE该权限允许对表或是或是表上特定的列或是视图进行更新操作。
DELETE该权限允许对表或是视图进行删除数据的操作。
TRUNCATE允许对表进行清空操作。
REFERENCES允许给参照列和被参照列上创建外键约束。
TRIGGER允许在表上创建触发器。
CREATE对于数据库允许在数据库上创建Schema对于Schema允许对Schema上创建数据库对象对于表空间允许把表或是索引指定到对应的表空间上。
CONNECT允许用户连接到指定的数据库上。
TEMPORARY或是TEMP允许在指定数据库的时候创建临时表。
EXECUTE允许执行某个函数。
USAGE对于程序语言来说允许使用指定的程序语言创建函数对于Schema来说允许查找该Schema下的对象对于序列来说允许使用currval和nextval函数对于外部封装器来说允许使用外部封装器来创建外部服务器对于外部服务器来说允许创建外部表。
ALL PRIVILEGES表示一次性给予可以授予的权限。
1.schema权限管理
首先,如果某个用户需要访问某张表,那么用户首先需要有访问该表所在schema的权限.默认只有schema的所属可以直接操作该schema,其它用户需要授权(public schma除外)
1.将schema的权限赋予给指定用户
例如,将创建对象权限赋予给brent用户:
test=# grant create on schema zzz to brent;
GRANT
例如,将schema中usage权限赋予给brent用户:
test=> grant usage on schema zzz to brent;
GRANT
例如,将schema中all权限赋予给brent用户,all表示一次性给予可以授予的所有权限
test=> grant all on schema zzz to brent;
GRANT
2.表权限管理
默认的,如果没有特别的授权,普通用户只能访问表所属为自己的表.超级用户可以访问任何表.如果要访问非自己的表,那么就需要对表进行授权.
当我们以brent用户想访问zzz模式下所属用户为test的abc表的时候就会报错:
test=> select user;
user
-------
brent
test=> select * from zzz.abc;
ERROR: permission denied for relation abc
1.grant,将表的查询和插入权限赋予给brent:
test=# grant select,insert on zzz.abc to brent;
GRANT
那么就可以进行查询了:
(1 row)
test=> \c test brent
You are now connected to database "test" as user "brent".
test=> select * from zzz.abc;
id
----
(0 rows)
2.revoke,将表的查询权限收回:
test=# set search_path=zzz;
SET
test=# \dt
List of relations
Schema | Name | Type | Owner
--------+------+-------+-------
zzz | abc | table | test
zzz | kkk | table | test
(2 rows)
test=# revoke select on zzz.abc from brent;
REVOKE
3.角色管理
我们除了可以将表的权限赋予给用户,我们还可以将角色赋予给用户,那么用户就会拥有赋予角色的相关权限:
test=# grant test to brent;
GRANT ROLE
test=# revoke test from brent;
REVOKE ROLE
4.查询表权限角色列表
使用\dp或者\z命令,可以查看表对象上已经分配的权限列表,如下:
test=# \dp abc
Access privileges
Schema | Name | Type | Access privileges | Column privileges | Policies
--------+------+-------+-------------------+-------------------+----------
zzz | abc | table | test=arwdDxt/test+| |
| | | brent=a/test +| |
| | | uuu=arwdDxt/test | |
(1 row)
详细的权限说明如下:
r -- SELECT ("读")
w -- UPDATE ("写")
a -- INSERT ("追加")
d -- DELETE
D -- TRUNCATE
x -- REFERENCES
t -- TRIGGER
X -- EXECUTE
U -- USAGE
C -- CREATE
c -- CONNECT
T -- TEMPORARY
arwdDxt -- ALL PRIVILEGES (对于表,对其他对象会变化)
* -- 用于前述特权的授权选项
/yyyy -- 授予该特权的角色
使用\du可以查看角色之间的成员关系:
test=# \du brent
List of roles
Role name | Attributes | Member of
-----------+------------+------------
brent | | {uuu,test}
其中uuu,test是brent的成员,也就是说uuu,test角色被赋予给了brent用户.\du类似与查看oracle中dba_role_privs
当我们决定收回某个表给予某个用户的权限的时候,除了需要收回表的权限,还需要检查用户的角色信息,保证用户的角色也没有相关的权限.
还可以通过查询information_schema.role_table_grants来了解某个用户具有的权限,类似于oralce中dba_tab[sys]_privs
test=# select * from information_schema.role_table_grants where grantee='brent';
grantor | grantee | table_catalog | table_schema | table_name | privilege_type | is_grantable | with_hierarchy
---------+---------+---------------+--------------+------------+----------------+--------------+----------------
brent | brent | test | brent | x | INSERT | YES | NO
brent | brent | test | brent | x | SELECT | YES | YES
brent | brent | test | brent | x | UPDATE | YES | NO
brent | brent | test | brent | x | DELETE | YES | NO
brent | brent | test | brent | x | TRUNCATE | YES | NO
brent | brent | test | brent | x | REFERENCES | YES | NO
brent | brent | test | brent | x | TRIGGER | YES | NO
brent | brent | test | brent | tt | INSERT | YES | NO
brent | brent | test | brent | tt | SELECT | YES | YES
brent | brent | test | brent | tt | UPDATE | YES | NO
brent | brent | test | brent | tt | DELETE | YES | NO
brent | brent | test | brent | tt | TRUNCATE | YES | NO
brent | brent | test | brent | tt | REFERENCES | YES | NO
brent | brent | test | brent | tt | TRIGGER | YES | NO
test | brent | test | zzz | abc | INSERT | YES | NO
(15 rows)

View file

@ -0,0 +1,115 @@
[postgres@vd ~]$ psql -d mydb -U appuser
psql: FATAL: remaining connection slots are reserved for non-replication superuser connections
#使用普通用户登录到数据库的时候数据库报错。并且拒绝链接访问。
[postgres@vd ~]$ psql -U postgres -d mydb
psql (9.5.4)
Type "help" for help.
mydb=# q
#而使用超级用户登录到该数据库却并没有提示错误。
[postgres@vd ~]$ psql -U appuser -d mydb
psql: FATAL: remaining connection slots are reserved for non-replication superuser connections
[postgres@vd ~]$ psql -U postgres -d mydb
psql (9.5.4)
Type "help" for help.
mydb=> select datname,datconnlimit from pg_database ;
datname | datconnlimit
-----------+--------------
template1 | -1
template0 | -1
postgres | -1
mydb | -1
(4 rows)
#数据库链接数并没有进行限制。也就是说链接上线不是数据库自身设置抛出。
mydb=# select count(*) from pg_stat_activity ;
count
-------
402
(1 row)
mydb=# select current_setting('max_connections');
current_setting
-----------------
410
(1 row)
mydb=# select current_setting('superuser_reserved_connections');
current_setting
-----------------
10
(1 row)
#用超级用户登录上去检查一下链接数是否正常。
#max_connections是总链接数
#superuser_reserved_connections是为超级用户预留的用户数
#也就是说 :普通用户最多可以登录数量=max_connections-superuser_reserved_connections
mydb=# select pg_terminate_backend(pid) from pg_stat_activity where pid<>pg_backend_pid() and pg_stat_activity.state='idle';
pg_terminate_backend
----------------------
t
...(省略)...
t
(352 row)
#经过协调相关人员同意将空闲用户都清除出去。使用pg_terminate_backend函数可以从数据库服务器端直接断开这些空闲链接。
#当然我自己的链接不能被断开。pg_backend_pid()是自己的pid号。
mydb=# q
[postgres@vd ~]$ psql -U appuser -d mydb
psql (9.5.4)
Type "help" for help.
mydb=> q
#再次使用普通用户链接就没有这个问题了。
追其发生原因,是业务方面不断增加任务需求,而开发人员为了增加任务同时工作数量,在中间件上不断增加链接数,而数据库端却没有增加,不增加数据库上的总链接数是因为怕数据库端内存不够而不敢无休止的增加,希望中间件能协调好复用链接,但没想到中间件最后解决的方法是直接占满数据库链接,起始中间件的日志中也有不少该报错,只是没有发现。
这里不得不吐嘈一下目前postgresql数据库还没有共享链接方式只能是来一个链接起一个进程非windows一般是使用中间件来控制链接过多的问题但是无论是使用什么中间件也不能无休止的增加数据库链接来解决业务需求过多的问题。