烦恼一般都是想太多了。

0%

以前就是了解过这个,但是由于生活需要,不能只干自己想干的,还必须干必须干的事情。那么就开始学习了一下java。
java se 最新的jdk是 jdk9,这与以前的有些不同呢,对于安装和配置都简单了很多很多了。

Read more »

MySQL查找效率的提高是通过为表建立索引来实现的,InnoDB更是如此,而其索引据说使用的是B-tree,一直不知道这是个什么东西,晚上抽空查看并了解了一下。

MySQL查询数据的过程

试想,MySQL把数据存储到磁盘上,查询的时候需要读取数据,如果没有建立一个索引的情况下。那么MySQL不得不逐个读取存储在数据文件内的内容,然后与查询进行匹配也得出数据,这是极其没有效率的事情。

在建立了索引的情况下,那么首先通过索引找到数据的位置,然后直接去磁盘上读取指定位置数据即可。

b-tree

这棵树与我们生活中理解的有点不同的,它只有Node(节点)叶子(leaf)。所有的数据存储在叶子上,并且所有的叶子都距离根节点的距离相同。每个Node存储了当前Node的键,子节点信息,父节点信息;叶子节点存储了数据。
b-tree
图中的蓝色方格内的是节点内的键,P[n]是子节点的指针。通过这样的格式,就把数据有序的组织了起来。
试想我们想要读取一个一行,其在ID上建立了索引,此行的索引值为75的情况下,这个过程是怎么样的。

  1. MySQL会读取索引根节点,然后与节点内的键进行比较,确定下一个节点在何处。这里 35 < 75,所以将会读取的下一个节点由指针P[3]确定。
  2. 读取子节点后,继续与节点内的键进行比较,确定指向的叶子节点,这里65 < 75 < 87,将会读取P[2]指向的叶子。
  3. 读取叶子后与气其内的键进行比较,得到数据。B-tree在叶子内存储的不是数据,而是数据的位置指针。
  4. MySQL定位到数据文件的对应位置,读取数据。

通过三次读取磁盘上的文件,就获得了真正的文件,效率大大的提高。

B-tree的性质

上图中是一个M为3的B树。 一个M阶的树满足下列条件:

1. 定义任意非叶子结点最多只有M个儿子;且M>2;

2. 根结点的儿子数为[2, M];

3. 除根结点以外的非叶子结点的儿子数为[M/2, M];

4. 每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)

5. 非叶子结点的关键字个数=指向儿子的指针个数-1;

6. 非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];

7. 非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;

8. 所有叶子结点位于同一层;

MySQL索引

MySQL使用 B-tree作为索引结构,每次读取磁盘上的一页,大小为16K。每一页,都是以键-指针的形式进行组织。 InnoDB使用 14-bit的指针。

聚簇索引

这个索引在叶子内保存的不是指针位置,而是数据了,更减少了一次磁盘IO。

二级索引

二级索引的叶子保存的行的主键,然后通过主键在聚簇索引中进行查询读取数据。如果主键很长的话,二级索引就会需要更多的空间,所以使用一个短的主键是非常有必要的。

MySQL索引的物理结构(官方文档 14.11.10节)

所有的InnoDB索引都B-tree,索引记录存储在叶子页上。默认索引页大小是16KB。

当新记录被插入到InnoDB聚簇索引的时候,InnoDB会尝试把当前页的1/16保留以便将来的插入或者更新。如果索引记录是按序插入的,那么插入页将会15/16充满。如果是随机的顺序插入的,其可能是在[1/2, 15,16]。如果索引页的充满比例不及1/2,InnoDB会试图压缩索引树来释放这一页。

改变InnoDB索引页大小是不支持的,也无法保证与非16KB索引页大小正常工作。编译和运行时InnoDB可能会出问题。实际上,被称为Barracuda新行格式ROW_FORMART=COMPRESSED假设索引页大小最大16KB,并且使用14-bit的指针。

g用不同索引页大小的数据文件和日志文件无法在实例之间无法移植。

curl 是一个命令行工具和「库」,目的是用来通过urls传输数据。其支持多个协议,多用来在命令行或者脚本来传输数据。通过其官方的这个入门的Tutorial可见其用处的广泛。
最新版本的curl可以通过其官方网站 curl.haxx.se获取

Read more »

Vundle是Vim bundle的一个简称,一个Vim插件管理器。开源项目地址位于Vundle.vim.git
只需要在.vimrc文件内加上几行,你就可以使用它来下载、卸载、管理各种位于github、官方插件仓库等地方的插件。

Read more »

HTTP Scripting

背景

这个文档假设你对HTTP和一些网络知识有了基本的了解。
随着越来越多的应用转移到了Web服务上,“HTTP Scripting”已经变得越来越被人们所需要。为了能自动的从网站上获得信息、伪造用户、传输数据或者上传数据到服务器上都是非常重要的任务。
Curl是一个命令行工具,用来进行所有类型的URL操作或者数据传输,但这个文档只把重心放在怎么用它来和一实际的HTTP服务器进行通信。我们假设你会使用curl --help或者curl --manual来获得一些更加基本的参考信息。
当然,Curl并不是万能的。它可以模拟请求,获取数据,发送数据,获得网站信息。你可能需要一些其他的脚本语言来把这些东西汇总在一起,或者你会需要做一些重复性的工作呢。

HTTP 协议

HTTP协议建立在TCP/IP之上,用来从网页服务器获取数据。这个协议也允许客户端以几种不同的方式向服务器发送数据,接下来我们就会看到。
HTTP是一个解释性的ASCII文本行由客户端发送到服务器以请求一个实际的动作,然后服务器会在返回客户端真正需要的内容之前返回一些文本行。
现在,curl充当一个客户端,发送一个请求。这个请求包含一种方式(GET, POST, HEAD等),一些请求头部或者请求主体。服务器返回状态行,响应头部和响应主体。这个“主体”怎么解释,由你的请求而定,比如会是HTML数据,或者一张图片。

观察协议

用curl的--verbose(-v)选项会展示出curl发送的是何种数据以及一些其他信息。
一般情况下这个选项已经够用,但如果还不够详细的时候,可以用--trace--tarce-ascii会更加详细。

curl --trace-ascii debugdump.txt http://www.baidu.com
curl --verbose http://www.baidu.com

观察时间

大多数时候我们确实想知道在整个请求回应过程中发生了什么,但某些时候我们可能只关注一下这耗费了多少时间。这个时候--trace-time选项就起了作用了。
这个选项会在每个跟踪输出的行前打印时间。

观察响应

默认情况下,curl会把响应发送到标准输出。你可以用-o或者-O选项来进行重定向。

URL

URL(Uniform Resource Locator)格式指的是你怎么样指定在网络上的地址或者资源。比如 www.baidu.com这样的地址。
RFC 3986是对这个的规范性文档。但是呢,你可能会发现,它的称呼是URI,而不是URL。

主机

大多数时候我们用主机名而不会直接指定IP地址,为了方便记忆。这个主机名到IP地址的解析,是由DNS来进行解析的,可能是公共的,也可能是内部的。
在某些时候,为了调试的需要,我们可以用--resolve为主机名指定一个不同的IP地址,而不是其原来定义的地址。如

curl --resolve www.baidu.com:80:www.163.com http://www.baidu.com

端口号

多数情况下,每个服务都有一个标准的端口号,比如HTTP的标准端口是80,但有的时候可能你会使用非标准的端口号如:

curl http://www.baidu.com:1234

有的时候,你也想指定一个代理:

curl --proxy http://proxy.example.org:4321 http://www.baidu.com

用户名与密码

在使用中可能有些网站需要账号密码才能进行访问。那你就可以这样:

curl http://user:password@www.baidu.com/
curl -u user:password http://www.baidu.com

但是,在当前的网站,可能已经不在用这样的方式进行用户的权限性验证了。而采用cookies或者表单了。

获取一个页面

GET

这是最简单的情况,如:

curl www.baidu.com

服务器返回的头部信息一般情况下是隐藏的,你可以用 --include(-i)选项让他显示出来。

仔细阅读了MySQL的官方参考文档,才会仔细的查看MySQL的这些元数据保存在什么地方。其实全都在INFORMATION_SCHEMA数据库内。我们可以从这里看到所有的信息。事实上我们用show {database | table} ... 语句展示的就是这里面的内容。

Read more »

MySQL 备份的方式

为什么需要备份

因为谁都无法保证,我们的存储设备,或者电源,或者是硬件等会在什么时候出问题,所以做一个备份,将有助于我们的数据的安全性的提高。如果你不在乎怎么给老板解释数据永久丢失无法找回,那么备份不备份并不重要了。

数据的存储方式

数据是以文件的格式存放在磁盘上,这些文件,由 mysqld 程序进行读取、写入等等操作。当然,我们也可以用文件系统上的命令来进行操作它,比如:复制、删除、修改等等操作,不过通常情况下是不推荐也不会这样去做的。由此而来,备份也多了另外一种方式。

备份的方式

逻辑备份与物理备份

从操作对象上来讲,我们可以对数据库最终的底层文件进行复制并转移到其他位置来进行备份;或者,我们可以用查询语句的方式,得到我们想要的结果,然后在需要的时候进行插入到新的位置来进行备份。这就是所谓的: 基于语句的备份(逻辑备份)和基于文件[块]的备份(物理备份)

完整备份与增量备份

有的时候,我们需要目标数据库所有的数据集合,而某些时候,我们只需要备份目标数据库从某一时间开始来变化过的数据。这就称为 完整备份 增量备份

可能忽略的问题

对于 mysqld 而言,底层数据、存储引擎、查询解析及缓存从上而下抽象分层。试想一下,我们采用逻辑备份物理备份 的时候可能会出现什么问题。
当我们需要查询读取数据的时候,存储引擎会去读取磁盘文件上的数据,这没有什么问题;但当我们进行更新查询的时候,问题就出现了,如果我们在进行文件复制进行备份的时候,有人在对数据进行更新,那很明显,就会引起数据的不一致性产生;同样,当我们在进行逻辑备份的查询更新的时候,也会有人在对数据更新,这同样会产生不一致。
就我理解而言,所谓的一致,是指在开始备份至备份完成这个时间窗口内所看到的数据没有产生变化。

考量

我们在备份的时候,有的时候,可能想要快速的备份,而有的时候,我们则需要考虑一下兼容性。所以在逻辑备份物理备份间会进行权衡考虑。
而当我们是不是要停止程序以中断服务的时候,就考虑采用热备份还是冷备份
当数据太大的时候,每次都采用完整备份并不是一个明智的选择,经常性增量备份配合偶尔的完整备份是一个不错的执行方式。

对数据一致性的保证

为了保证我们备份数据的一致性,我们必须保证在备份时间窗口内没有数据更新 或者 我们看到的数据始终是不变的。
已经有一些方法来达成这个目的。

flush配合读锁表

mysql> flush tables with read lock;

这个语句会将缓存刷新到磁盘,关闭所有打开表,读锁定所有表。

1.建立一个测试表。

mysql> create table ssdd.tbl( id int auto_increment, name varchar(20), primary key (id)) engine=MyISAM;
mysql> insert into ssdd.tbl(name) values('angel');

我们不妨自己测试一下,首先我对 ssdd.tbl 表进行查询一下,这会导致 mysqld 打开这个表。

mysql> select id from ssdd.tbl;
+----+
| id |
+----+
|  1 |
+----+

2.查看打开文件
然后我们用 Linux的 lsof 命令看一下 打开的文件情况。

[root@VM_0_6_centos ~]# lsof | grep tbl
COMMAND     PID    USER   FD      TYPE             DEVICE SIZE/OFF       NODE NAME
mysqld    14634   mysql   16u      REG              252,1     2048     368758 /var/lib/mysql/ssdd/tbl.MYI
mysqld    14634   mysql   17u      REG              252,1       20     368759 /var/lib/mysql/ssdd/tbl.MYD

3.锁

mysql> flush tables with read lock;

4.查看文件打开情况

[root@VM_0_6_centos ~]# lsof | grep tbl
[root@VM_0_6_centos ~]#

输出表明,这表文件已经被关闭了。
5.查询数据(另外一个终端)

mysql> select id from ssdd.tbl;
+----+
| id |
+----+
|  1 |
+----+

6.更新一下数据试试

mysql> update ssdd.tbl set id=id+1;

你会发现,卡住了,是的,因为表是被读锁定的。那么我们下一步解锁。

7.解锁

mysql> unlock tables;

这样第6步更新才会成功。
对于MyISAM表,mysqlhotcopy采用的就是这种方式进行备份。当然,我们可以自己手动执行给表上锁被刷新语句后,自行进行复制文件进行备份。

对于事务表

对于InnoDB,最好看一下其简单的概念。MySQL架构简介
常规概念上来说,MyISAMInnoDB引擎,一个不支持事务,一个支持事务。但在数据的存储方式上,也有不同。
MyISAM表的数据保存在三个文件内 tbl.{frm,MYD,MYI}
InnoDB表的数据并存储在由多个数据文件构成的表空间内,同时,重做日志会存储在重做日志文件内。数据文件重做文件是两个非常重要的概念,对于InnoDB表而言。注意:二进制日志与重做日志是不同滴
我们可以通过实例来查看一下其中的一些细节。
1.创建一个 innodb 表。

create table ssdd.tbl2 ( a int auto_increment, b char(20), primary key (a)) engine=innodb;

2.查看表的存储文件

shell> ls -1 /var/lib/mysql/ssdd    --/var/lib/mysql/ssdd 是数据库目录
db.opt
t_ability.frm
t_ability.MYD
t_ability.MYI
tbl2.frm
tbl.frm
tbl.MYD
tbl.MYI

我们只看到了 tbl2.frm 也就是表和列定义文件,而并没有 如同 MyISAM表那样的数据文件和索引文件,这都存储于表 InnoDB的表空间内,默认情况下,是在datadir 中的 ibdata1 文件。
有人可能会反对,说innodb_file_per_table 配置可以每个表使用不同的 表空间文件,这当然是可以的。

对那些想把特定表格移到分离物理磁盘的用户,或者那些希望快速恢复单个表的备份而无须打断其余InnoDB表的使用的用户,使用多表空间会是有益的。

但我们要意识到,innodb_file_per_table选项只会影响表的创建。也就是说,对于已在共享表空间创建的表,不会受到这个选项的影响;而如果在创建表后,关闭这个选项,已创建的使用单独表空间的表,也不会受到影响。
共享表空间,依然是需要的,因为InnoDB把内部数据词典和未作日志放在这个文件中。

配置innodb_file_per_table选项,并重启服务器,然后建立一个表。

create table ssdd.tbl3 ( a int auto_increment, b char(20), primary key (a)) engine=innodb;

查看目录:

[root@VM_0_6_centos mysql]# ls -1 /var/lib/mysql/ssdd
db.opt
t_ability.frm
t_ability.MYD
t_ability.MYI
tbl2.frm
tbl3.frm
tbl3.ibd
tbl.frm
tbl.MYD
tbl.MYI

表tbl3有了自己的.ibd表空间数据文件。
但是,即使是这样,我们在进行物理备份的时候依然会很头疼。因为我们不仅要备份表的数据文件,还要备份一些数据字典文件(位于系统共享表空间内),还有重做日志(ib_logfile0/1)等等。
而且,从概念上讲,磁盘上的数据文件与InnoDB引擎在内存中的缓存池、二次缓存的数据并不一定是一致的。在事务已提交到重做日志,但还未更新到数据文件之间的时间窗口会产生很大的问题。