MySQL Hash索引和B-Tree索引的区别

MySQL Hash索引和B-Tree索引的区别究竟在哪里呢?相信很多人都有这样的疑问,下文对两者的区别进行了详细的分析,供您参考。

MySQL Hash索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引。
可 能很多人又有疑问了,既然 Hash 索引的效率要比 B-Tree 高很多,为什么大家不都用 Hash 索引而还要使用 B-Tree 索引呢?任何事物都是有两面性的,Hash 索引也一样,虽然 Hash 索引效率高,但是 Hash 索引本身由于其特殊性也带来了很多限制和弊端,主要有以下这些。

(1)MySQL Hash索引仅仅能满足”=”,”IN”和”<=>”查询,不能使用范围查询。

由于 MySQL Hash索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和Hash运算前完全一样。

(2)MySQL Hash索引无法被用来避免数据的排序操作。

由于 MySQL Hash索引中存放的是经过 Hash 计算之后的 Hash 值,而且Hash值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算;

(3)MySQL Hash索引不能利用部分索引键查询。

对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。

(4)MySQL Hash索引在任何时候都不能避免表扫描。

前面已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。

(5)MySQL Hash索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高。

对于选择性比较低的索引键,如果创建 Hash 索引,那么将会存在大量记录指针信息存于同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。

MySQL SHOW命令汇总

a. show tablesshow tables from database_name; — 显示当前数据库中所有表的名称
b. show databases; — 显示 mysql 中所有数据库的名称
c. show columns from table_name from database_name;show columns from database_name.table_name; — 显示表中列名称
d. show grants for user_name; — 显示一个用户的权限,显示结果类似于grant 命令
e. show index from table_name; — 显示表的索引
f. show status; — 显示一些系统特定资源的信息,例如,正在运行的线程数量
g. show variables; — 显示系统变量的名称和值
h. show processlist; — 显示系统中正在运行的所有进程,也就是当前正在执行的查询。大多数用户可以查看他们自己的进程,但是如果他们拥有process权限,就可以查看所有人的进程,包括密码。
i. show table status; — 显示当前使用或者指定的database中的每个表的信息。信息包括表类型和表的最新更新时间
j. show privileges; — 显示服务器所支持的不同权限
k. show create database database_name; — 显示create database 语句是否能够创建指定的数据库
l. show create table table_name;— 显示create database 语句是否能够创建指定的数据库
m. show engies; — 显示安装以后可用的存储引擎和默认引擎。
n. show innodb status; — 显示innoDB存储引擎的状态
o. show logs; — 显示BDB存储引擎的日志
p. show warnings; — 显示最后一个执行的语句所产生的错误、警告和通知
q. show errors; — 只显示最后一个执行语句所产生的错误
r. show [storage] engines; –显示安装后的可用存储引擎和默认引擎
s. show procedure status –显示数据库中所有存储的存储过程基本信息,包括所属数据库,存储过程名称,创建时间等
t. show create procedure sp_name –显示某一个存储过程的详细信息

语法:MySQL中INSERT INTO SELECT的使用

语法介绍

有三张表a、b、c,现在需要从表b和表c中分别查几个字段的值插入到表a中对应的字段。对于这种情况,可以使用如下的语句来实现:

上面的语句比较适合两个表的数据互插,如果多个表就不适应了。对于多个表,可以先将需要查询的字段JOIN起来,然后组成一个视图后再SELECT FROM就可以了:

其中f1是表b的字段,f2是表c的字段,通过JOIN查询就将分别来自表b和表c的字段进行了组合,然后再通过SELECT嵌套查询插入到表a中,这样就满足了这个场景了,如果需要不止2个表,那么可以多个JOIN的形式来组合字段。

语法错误注意

需要注意的是嵌套查询部分最后一定要有设置表别名,如下:

即最后的AS tb是必须的(tb这个名称可以随意取),即指定一个别名。每个派生出来的新表都必须指定别名,否则在mysql中会报如下错误:
ERROR 1248 (42000): Every derived TABLE must have its own alias

另外,MySQL中INSERT INTO SELECT不能加VALUES,即不能写成如下形式:

否则也会报错:You have an error in your SQL syntax

NetBeans常用快捷键

1、Ctrl-Tab:在打开的文件之间切换;

2、Ctrl-N:在当前打开的项目里新建文件;

3、Ctrl-F:当前文件查找匹配的字符(支持正则);

4、Ctrl-H:当前文件查找、替换匹配的字符(支持正则,这里正则显得比较重要);

5、Ctrl-Shift-↑↓:光标所在行向上或者向下复制;

6、Ctrl-[:光标所在的位置首尾标识符之间移动({},ul );

7、Ctrl-K:插入当前文档或者当前方法里匹配相关的关键词;

8、Ctrl-B:跳到光标所在位置的函数定义说明文档所在的位置(与Ctrl-鼠标左键差不多);

9、Ctrl-G:输入数字跳到当前文档所在行;

10、Ctrl-Shift-1/2/3:显示当前文件所在项目/文件位置/添加到收藏;

11、Ctrl-D:删除当前行;

12、Ctrl-E:剪切当前行;

13、Ctrl-/:注释当前行或者注释所选的多行;

14、Ctrl-Shift-/:去掉注释当前行或者去掉注释所选的多行;

15、Alt-F7:查找当前函数使用实例;

16、Ctrl-Shift-F:当前打开项目查找匹配的字符(支持正则);

17、Ctrl-Shift-H:当前打开项目查找、替换匹配的字符(支持正则,这里正则显得比较重要);

18、Ctrl-P:显示光标所在方法的参数;

19、Alt-Shift-↑↓←→:当前行上下左右移动;

20、Ctrl-Shilt-Space:显示当前方法详细说明文档;

21、Alt-Enter:显示语法错误;

22、Ctrl-Shift-C:开启或者关闭当前注释;

23、Alt-←:上一个编辑的地方;

24、Alt-→:下一个编辑的地方;

25、Ctrl-Q:最后一个编辑的地方;

这里只介绍了平时常用到的,另外一些有关运行、编译、单元测试以及调试的快捷键都没有罗列。

phpMyAdmin密码设置

在使用phpMyAdmin操作数据库时,首先需要设置mysql的root用户的密码。具体操作参考前一篇博文。设置完mysql的root密码之后,需要对phpMyAdmin的登录进行一些配置。

未经配置的phpMyAdmin很不安全,容易受到攻击,或者根本无法正常使用,phpMyAdmin有3种授权模式:
– cookie: 显示一个web登录页面,输入mysql的用户名和密码,然后进入管理界面
– http: 显示1个windows登录框,输入mysql的用户名和密码,然和进入管理
– config: 把mysql用户名和密码直接填入config.inc.php,不显示登录界面,直接进入管理界面

具体的参数配置如下所示:

各参数的含义从命名中可以很清楚的看出来。根据自己的需要进行必要的配置即可。

mysql远程连接错误1130的解决方法

解决远程连接mysql错误1130代码的方法

今天在用远程连接Mysql服务器的数据库,不管怎么弄都是连接不到,错误代码是1130,ERROR 1130: Host 192.168.2.159 is not allowed to connect to this MySQL server
猜想是无法给远程连接的用户权限问题。结果这样子操作mysql库,即可解决。在本机登入mysql后,更改 “mysql” 数据库里的 “user” 表里的 “host” 项,从”localhost”改称’%’。。

第一句:以权限用户root登录
第二句:选择mysql库
第三句:查看mysql库中的user表的host值(即可进行连接访问的主机/IP名称)
第四句:修改host值(以通配符%的内容增加主机/IP地址),当然也可以直接增加IP地址
第五句:刷新MySQL的系统权限相关表
第六句:再重新查看user表时,有修改。。
重起mysql服务即可完成。


本机的mysql数据库中有两条user=’root’的记录,将其中一条host=’localhost’的host修改为’%’后,虽然可以通过远程访问数据库了,但是使用localhost或者127.0.0.1又无法访问数据库了。

经过一番折腾,发现可以通过创建用户的方法来解决这个问题。不需要修改user表中的任何数据,在本地用root登陆mysql后,执行下面的语句,创建用户名为’root’,密码为’123456’的用户。执行完以后,查看user表,发现新增了一条host=’%’,user=’root’的记录,并且各项权限与其它’root’一样,再次使用192.168.1.13进行访问,发现可以正常访问了。

如果访问还有问题,可以执行一下flush privileges;

MySQL修改root密码的各种方法整理

整理了以下四种在MySQL中修改root密码的方法,可能对大家有所帮助!

方法1: 用SET PASSWORD命令

方法2:用mysqladmin

如果root已经设置过密码,采用如下方法

方法3: 用UPDATE直接编辑user表

在丢失root密码的时候,可以这样

返回值 还是 异常?

返回值 还是 异常?

1 异常

1.1 好处
提高代码可读性

根据区块来区分开正常流程和异常处理

可迅速追溯到错误源头

类库定义的异常基类本身能提供很多的信息,如InnerException,StackTrace等

1.2 坏处
阅读代码时,人眼无法轻易辨认出隐藏的异常

假设DoSomething1中会抛出异常,通过代码无法一眼看出DoSomething2是否会被执行。
如果需要确认DoSomething2是否会被执行,你需要了解DoSomething1会抛出哪些异常。
如果DoSomething1有关于会抛出的异常说明,那还算容易,否则你需要查看整个DoSo-
mething1调用树结构。

性能开销大

语言通用性问题

假如各模块由不同的语言写成,则只能在模块内使用异常。换言之,各语言的异常处理不具备通用性。

2 返回值

2.1 好处
没有异常的性能问题

单看代码,很容易辨认程序处理流程

客户代码编写者看到返回值,会有去处理这些返回值的责任。

2.2 坏处
特定场景使用限制

构造函数,线程处理函数等不允许有返回值的情况,以及返回值被用作其他用途的情况

客户代码不够清晰

3 我的理解
追求 稳定 高性能 的程序,慎用异常。

团队应为异常处理方式建立规范,以保证项目的统一(Consistency)性。

正确的使用异常,避免异常混入程序控制流。

模块间接口应采用返回值方式。自己模块内的异常确保自己进行了处理。

4 参考文章
Cleaner, more elegant, and harder to recognize—By Raymond Chen
Making Wrong Code Look Wrong—Joel on software
“拥抱”异常,还是,”固守”返回值?—DCCMX

数据库设计准则(第一、第二、第三范式说明)

I、关系数据库设计范式介绍

1.1 第一范式(1NF)无重复的列

所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式就是无重复的列。

说明:在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。

1.2 第二范式(2NF)属性完全依赖于主键[消除部分子函数依赖]

第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。例如员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是惟一的,因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主码。

第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是属性完全依赖于主键。

1.3 第三范式(3NF)属性不依赖于其它非主属性[消除传递依赖]

满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在的员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。简而言之,第三范式就是属性不依赖于其它非主属性。

II、范式应用实例剖析

下面以一个学校的学生系统为例分析说明,这几个范式的应用。首先第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。在当前的任何关系数据库管理系统(DBMS)中,傻瓜也不可能做出不符合第一范式的数据库,因为这些DBMS不允许你把数据库表的一列再分成二列或多列。因此,你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的。

首先我们确定一下要设计的内容包括那些。学号、学生姓名、年龄、性别、课程、课程学分、系别、学科成绩,系办地址、系办电话等信息。为了简单我们暂时只考虑这些字段信息。我们对于这些信息,说关心的问题有如下几个方面。

  • 学生有那些基本信息

  • 学生选了那些课,成绩是什么

  • 每个课的学分是多少

  • 学生属于那个系,系的基本信息是什么。

2.1 第二范式(2NF)实例分析

首先我们考虑,把所有这些信息放到一个表中(学号,学生姓名、年龄、性别、课程、课程学分、系别、学科成绩,系办地址、系办电话)下面存在如下的依赖关系。

(学号)→ (姓名, 年龄,性别,系别,系办地址、系办电话)
(课程名称) → (学分)
(学号,课程)→ (学科成绩)

2.1.1 问题分析

因此不满足第二范式的要求,会产生如下问题

  • 数据冗余: 同一门课程由n个学生选修,”学分”就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次。

  • 更新异常:
    1) 若调整了某门课程的学分,数据表中所有行的”学分”值都要更新,否则会出现同一门课程学分不同的情况。
    2)假设要开设一门新的课程,暂时还没有人选修。这样,由于还没有”学号”关键字,课程名称和学分也无法记录入数据库。

  • 删除异常 : 假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称和学分信息也被删除了。很显然,这也会导致插入异常。

2.1.2 解决方案

把选课关系表SelectCourse改为如下三个表:

  • 学生:Student(学号,姓名, 年龄,性别,系别,系办地址、系办电话);

  • 课程:Course(课程名称, 学分);

  • 选课关系:SelectCourse(学号, 课程名称, 成绩)。

2.2 第三范式(3NF)实例分析

接着看上面的学生表Student(学号,姓名, 年龄,性别,系别,系办地址、系办电话),关键字为单一关键字”学号”,因为存在如下决定关系:

(学号)→ (姓名, 年龄,性别,系别,系办地址、系办电话)

但是还存在下面的决定关系

(学号) → (所在学院)→(学院地点, 学院电话)

即存在非关键字段”学院地点”、”学院电话”对关键字段”学号”的传递函数依赖。

它也会存在数据冗余、更新异常、插入异常和删除异常的情况。 (數據的更新,刪除異常這里就不分析了,可以參照2.1.1進行分析)

根据第三范式把学生关系表分为如下两个表就可以滿足第三范式了:

  • 学生:(学号, 姓名, 年龄, 性别,系别);
  • 系别:(系别, 系办地址、系办电话)。

总结

上面的数据库表就是符合I,II,III范式的,消除了数据冗余、更新异常、插入异常和删除异常。

MySQL出现Waiting for table metadata lock的原因以及解决方法

MySQL在进行alter table等DDL操作时,有时会出现Waiting for table metadata lock的等待场景。而且,一旦alter table TableA的操作停滞在Waiting for table metadata lock的状态,后续对TableA的任何操作(包括读)都无法进行,因为他们也会在Opening tables的阶段进入到Waiting for table metadata lock的锁等待队列。如果是产品环境的核心表出现了这样的锁等待队列,就会造成灾难性的后果。

造成alter table产生Waiting for table metadata lock的原因其实很简单,一般是以下几个简单的场景:

场景一:长事物运行,阻塞DDL,继而阻塞所有同表的后续操作

通过show processlist可以看到TableA上有正在进行的操作(包括读),此时alter table语句无法获取到metadata 独占锁,会进行等待。

这是最基本的一种情形,这个和mysql 5.6中的online ddl并不冲突。一般alter table的操作过程中(见下图),在after create步骤会获取metadata 独占锁,当进行到altering table的过程时(通常是最花时间的步骤),对该表的读写都可以正常进行,这就是online ddl的表现,并不会像之前在整个alter table过程中阻塞写入。(当然,也并不是所有类型的alter操作都能online的,具体可以参见官方手册:http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html)
处理方法: kill 掉 DDL所在的session.

场景二:未提交事物,阻塞DDL,继而阻塞所有同表的后续操作

通过show processlist看不到TableA上有任何操作,但实际上存在有未提交的事务,可以在 information_schema.innodb_trx中查看到。在事务没有完成之前,TableA上的锁不会释放,alter table同样获取不到metadata的独占锁。

处理方法:通过 select * from information_schema.innodb_trx\G, 找到未提交事物的sid, 然后 kill 掉,让其回滚。

场景三:

通过show processlist看不到TableA上有任何操作,在information_schema.innodb_trx中也没有任何进行中的事务。这很可能是因为在一个显式的事务中,对TableA进行了一个失败的操作(比如查询了一个不存在的字段),这时事务没有开始,但是失败语句获取到的锁依然有效,没有释放。从performance_schema.events_statements_current表中可以查到失败的语句。

官方手册上对此的说明如下:

If the server acquires metadata locks for a statement that is syntactically valid but fails during execution, it does not release the locks early. Lock release is still deferred to the end of the transaction because the failed statement is written to the binary log and the locks protect log consistency.

也就是说除了语法错误,其他错误语句获取到的锁在这个事务提交或回滚之前,仍然不会释放掉。because the failed statement is written to the binary log and the locks protect log consistency 但是解释这一行为的原因很难理解,因为错误的语句根本不会被记录到二进制日志。

处理方法:通过performance_schema.events_statements_current找到其sid, kill 掉该session. 也可以 kill 掉DDL所在的session.

总之,alter table的语句是很危险的(其实他的危险其实是未提交事物或者长事务导致的),在操作之前最好确认对要操作的表没有任何进行中的操作、没有未提交事务、也没有显式事务中的报错语句。如果有alter table的维护任务,在无人监管的时候运行,最好通过lock_wait_timeout设置好超时时间,避免长时间的metedata锁等待。