有的时候会把md5这种16个字节的字符串,通过两个big int类型的数字来存放,这样查询会快一些,不过当得到一个md5后来进行查询就不是很方便了。幸好mysql提供了诸多的函数可以方便的实现你想要的内容:
1 通过set来设置一个md5的变量
2 后续通过left和right两个函数来取得前后的8个字节,通过conv转换为10进制,可以方便的实现比较
set @md5_var='315a6e9d2114d67c75f684a9f8638413';select count(*) from *** where md1=conv(left(@md5_var, 16), 16, 10) and md2=conv(right(@md5_var, 16), 16, 10);
以前大部分时间使用的是mysql的myisam或者innodb的引擎,这两种都是基于行的方式来存储数据,这样尽量的避免随机写,在写的时候会快一些,而且要取得一行的数据也会比较快的可以索引到。不过随着数据量的增加,尤其是在数据分析的领域,动不动就是上T的数据,即使分库分表来进行存储,统计起来也会变得很慢,因为行式存储引擎,不仅数据需要空间,索引也是需要很大的空间的。磁盘IO常常成为瓶颈。尤其是很多行里面的数据大多大同小异,如用户的id或者guid这些字段的值,大量的存在在一个表中。
于是就有了列式的存储方法,按照列来组织数据,同时由于列中的数据重复度还蛮高的,于是又有了很大的压缩的可能。
按照列来存储数据,存储方式的改变,导致不能通过之前行模式下的索引的方式来组织查询了,于是需要引入一套新的查询的方式。在Infobright中,采用是知识网格的方式来实现高效的查询。
来看看基于brighthouse的列存储引擎的Mysql的另外封装Infobright是如何来实现基于列式存储的知识网格分析型数据库的。
Infobright采用了和MySQL一致的构架,分为两层。上层是服务及应用管理,下层是存储引擎。
Infobright的默认存储引擎是brighthouse,但是Infobright还可以支持其他的存储引擎,比如MyISAM、MRG_MyISAM、Memory、CSV。
Infobright通过三层来组织数据,分别是DP(Data Pack)、DPN(Data Pack Node)、KN(Knowledge Node)。
而在这三层之上就是无比强大的知识网络(Knowledge Grid)。
[caption id="attachment_689" align="aligncenter" width="616" caption="Infobright的总体构架图"][/caption]
数据块(DP)是存储的最低层,列中每64K个单元组成一个DP。
DP比列更小,具有更好的压缩比率;又比单个数据单元更大,具有更好的查询性能。
数据块节点(DPN),DPN和DP之间是一对一的关系。DPN记录着每一个DP里面存储和压缩的一些统计数据,包括最大值、最小值、null的个数、单元总数count、sum等等。是这块数据的一些元数据的简单抽象,如一个多元组:(最小值,至大致,null的个数,求和结果,条目数,...)
KN里面存储着指向DP之间或者列之间关系的一些元数据集合,比如值发生的范围(MIin_Max)、列数据之间的关联。大部分的KN数据是装载数据的时候产生的,另外一些事是查询的时候产生。更高一层的元数据的抽象。
DPN和KN都是比较小的,可以放到内存中来。
基于DP和KN层,之上是知识网格(Knowledge Grid),Knowledge Grid构架是Infobright高性能的重要原因。
KN里面有如下几个部分:Histogram、CMAP、P-2-P。
Histogram(数据柱状图)用来提高数字类型(比如date,time,decimal)的查询的性能。Histogram是装载数据的时候就产生的。
根据这个数据列的大小返回分成1024个等份。看看DP中的数据在那个段,就设置为1
CMAP字符映射表:存储DP中的某个字符在某个位置的信息,一般在like字符串匹配查询中会用到。
P-2-P行集映射矩阵:用于join操作时不同表中的行集之间的关系
Infobright的工作原理:
粗糙集(Rough Sets)是Infobright的核心技术之一,即查询时不一定要精确的一步到位,而是根据DPN和KN中的信息进行知识的推理,不断所以比较的范围,从大的粗糙结果到后面的精确结果。
Infobright在执行查询的时候会根据知识网格(Knowledge Grid)把DP分成三类:
相关的DP(Relevant Packs),满足查询条件限制的DP
不相关的DP(Irrelevant Packs),不满足查询条件限制的DP
可疑的DP(Suspect Packs),DP里面的数据部分满足查询条件的限制
[caption id="attachment_692" align="aligncenter" width="640" caption="infobright知识网格原理图"][/caption]
如图所示,每一列总共有5个DP,说明这个表的总共的行数<= 5*65535.
根据限制条件是A>6,从DPN中就可以得知,A1、A2、A4就是不相关的DP,A3是相关的DP,A5是可疑的DP。
那么执行查询的时候只需要计算B5中满足条件的记录的和然后加上Sum(B3),Sum(B3)是已知的。
此时只需要解压缩B5这个DP,整个处理的数据量就会变得小了许多。
从上面的分析可以知道,Infobright能够很高效地执行一些查询,而且执行的时候where语句的区分度越高越好。where区分度高可以更精确地确认是否是相关DP或者是不相关DP亦或是可以DP,尽可能减少DP的数量、减少解压缩带来的性能损耗。
在做条件判断的使用,一般会用到上一章所讲到的Histogram和CMAP,它们能够有效地提高查询性能。
如果再有一个查询是这样的:SELECT MAX(A) FROM T WHERE B > 15;
[caption id="attachment_695" align="aligncenter" width="616" caption="infobright内部查询的推导图"][/caption]
上述查询语句经过了bcd四个步骤:
b:根据B>15,将(A5,B5)排除。
c:根据MAX(A),A4中最大是10,A3中最小是18,说明MAX(A)至少大于18,进一步的查询变成:
ROUGH ID FROM T WHERE B>15 AND A>18;
再次筛选掉一些可疑的DP,剩下(A1,B1) 和 (A3,B3)。在引入ORDER BY命令
ROUGH ID FROM T WHERE B>15 AND A>18 ...
今天遭遇mysql的一次小小的意外,导致表里面的所有数据都被update了。过程是这样的:
表里有一个自增长的id,所以写sql语句的时候是这样的,先insert,如果key重复的话,再update。
结果插入一条记录的时候,没有填写id,原以为会insert,结果insert后提示key重复,于是在update,这下子就把整个表给update了。
try {
$id = $this->insert($row);
return true;
} catch (QDB_Exception_DuplicateKey $e) {
return $this->updateRow($row);
} catch (QException $e) {
return false;
}
找了一下原因,发现这个表被人恶搞了一下,把自增长的id设置为4294967295,结果一插入就提示下面的信息了:
Duplicate entry '4294967295'
通过如下命令修改自增长的id到一个理性值后ok:
ALTER TABLE tbl AUTO_INCREMENT = 100;
通过:
select last_insert_id() ;能够得到当前的自增长id值
mysql的官方文档:
Use a large enough integer data type for the
AUTO_INCREMENT column to hold the maximum ...
mysql5.0以后支持load data的时候有临时变量来辅助。
今天遇到表中是md5 binary类型的,需要将一个hex过后的文本导入的。
于是利用临时变量的特性来帮助解决了这个问题,比起一条条的insert的速度快多了。
一条条的insert mysql,php执行1ms一次,1秒只能执行1000次。一般myisam的存储引擎,一秒能够支持5000来此插入的。
load data infile '/tmp/a.txt' into table a (@var) set md5 = unhex(@var)
mysql真是强大啊!
一些不太常用的命令:
mysql支持linux下的搜索功能,ctrl+r就开启了命令搜索;
如果输入了长命令发现错了,只需要输入\c就可以取消命令;
命令或者表名、或者列名自动补齐:
MySQL 命令自动补齐功能
方法一、
vi /etc/my.cnf
[mysql]
#no-auto-rehash
auto-rehash #添加auto-rehash
在重启一下mysql服务,补全命令按 TAB 建
捉着在mysql启动时加参数auto-rehash
mysqld_safe --user=mysql --auto-rehash &
mysql的操作历史在那里看到:用户的根目录下有一个.mysql_history;
最近用子查询导致sql的效率非常低下,后来改为左链接left join操作后就好了许多,查阅了一下mysql的官方文档发现:
http://dev.mysql.com/doc/refman/5.1/en/rewriting-subqueries.html
A LEFT [OUTER] JOIN can be faster than an equivalent subquery because the server might be able to optimize it better—a fact that is not specific to MySQL Server ...
今天遇到一个奇怪得问题,就是启动mysql时不停的重启,呵呵,不停得重启了几次,都不行,没有太注意mysql得错误提示信息。
无意间观察一下发现,提示我 没有空间来存放pid文件啦。原来是硬盘已经满了。呵呵,下次哪位同学遇到不停重启得问题,
可以先df -h 看看是不是mysql datadir或者pid 文件所在的分区下的硬盘是否已经满了。
vim /etc/my.cnf可以看到datadir和pid文件的路径信息。
记录一下常用得几个mysql的命令吧:
1 启动/关闭:
cd /usr/local/mysql/bin
启动服务:./mysqld_safe --user=mysql &
关闭服务:./mysqladmin shutdown
进入MySQL:./mysql -u用户名 -h密码
2 常用的mysql操作命令:
显示数据库:show databases;
显示表:show tables;
建库:create database test;
进入库:use test;
建表:create table user(id int unsigned not null, age smallint not null, name char(20) not null);
建索引:create index index_id on user(id);
插入数据:insert into user values (12345, 23, ‘meinv’), (23456,23,’shuaige’);
导入数据:load data infile ‘/tmp/user.txt’ into table user fields terminated by ‘,’;
导出数据:直接拷贝表文件,或者select * from user into outfile ...
当数据量到达一定的量级之后,一般而言是10万。数据库mysql的索引将变得尤其的重要。
没有索引的话,mysql将会遍历整个表来查询满足的条件,大家想想遍历一遍1000万的数据需要多长的时间呢。
不过,在使用mysql的索引的时候,小小的注意几点可能会给存储性能以及执行查询和更新语句的性能带来很大的提高。
根据实际操作中的一些经验,总结几条如下:
1 只有需要用到了字段才为其简历索引,索引也是为占用存储空间的。如果索引过多的话,更新的时候也要更新索引部分的数据,性能就不怎么好了。
2 简短的字符串类的索引,如char、varchar、text的列而言,如果能够确定索引的长度的就确定索引的长度,不要使用一个长长的索引长度,性能影响很大
3 除了主键以为还可以使用unique索引,一一对应的索引的话,如果hash表其查询的性能肯定是卓越的。因为只需要o(1)的复杂度晒。
4 遵从mysql的最左前缀的复合索引规则,根据where语句中使用的方式来定义复合的索引。例如建立了这么一个复合的索引(col1,col2,col3),那么在where时可以使用的索引有where col1 = **或者where col1 = ** and col2 = **或者 where col1 = ** and col2 = ** and col3 = **
最后的话,explain你的sql语句看看是否使用到索引,如果没有,赶快去加上吧。
呵呵,还要注意一点哦,mysql提供的丰富多彩的字符串函数并不是一个很好的东东哦,这些函数应用在where中的列上时是不会使用到索引的。如 where ucase(col1) = ***,即使col1上有索引,由于使用了函数转换,mysql并不能使用上之前建立的索引值。
使用mysql的api时,常常会遇到错误码。
总结了一下这些错误码的含义,方便后续程序遇到时来查看,呵呵。
1005:创建表失败
1006:创建数据库失败
1007:数据库已存在,创建数据库失败
1008:数据库不存在,删除数据库失败
1009:不能删除数据库文件导致删除数据库失败
1010:不能删除数据目录导致删除数据库失败
1011:删除数据库文件失败
1012:不能读取系统表中的记录
1020:记录已被其他用户修改
1021:硬盘剩余空间不足,请加大硬盘可用空间
1022:关键字重复,更改记录失败
1023:关闭时发生错误
1024:读文件错误
1025:更改名字时发生错误
1026:写文件错误
1032:记录不存在
1036:数据表是只读的,不能对它进行修改
1037:系统内存不足,请重启数据库或重启服务器
1038:用于排序的内存不足,请增大排序缓冲区
1040:已到达数据库的最大连接数,请加大数据库可用连接数
1041:系统内存不足
1042:无效的主机名
1043:无效连接
1044:当前用户没有访问数据库的权限
1045:不能连接数据库,用户名或密码错误
1048:字段不能为空
1049:数据库不存在
1050:数据表已存在
1051:数据表不存在
1054:字段不存在
1065:无效的SQL语句,SQL语句为空
1081:不能建立Socket连接
1114:数据表已满,不能容纳任何记录
1116:打开的数据表太多
1129:数据库出现异常,请重启数据库
1130:连接数据库失败,没有连接数据库的权限
1133:数据库用户不存在
1141:当前用户无权访问数据库
1142:当前用户无权访问数据表
1143:当前用户无权访问数据表中的字段
1146:数据表不存在
1147:未定义用户对数据表的访问权限
1149:SQL语句语法错误
1158:网络错误,出现读错误,请检查网络连接状况
1159:网络错误,读超时,请检查网络连接状况
1160:网络错误,出现写错误,请检查网络连接状况
1161:网络错误,写超时,请检查网络连接状况
1062:字段值重复,入库失败
1169:字段值重复,更新记录失败
1177:打开数据表失败
1180:提交事务失败
1181:回滚事务失败
1203:当前用户和数据库建立的连接已到达数据库的最大连接数,请增大可用的数据库连接数或重启数据库
1205:加锁超时
1211:当前用户没有创建用户的权限
1216:外键约束检查失败,更新子表记录失败
1217:外键约束检查失败,删除或修改主表记录失败
1226:当前用户使用的资源已超过所允许的资源,请重启数据库或重启服务器
1227:权限不足,您无权进行此操作
1235:MySQL版本过低,不具有本功能