MySQL零碎积累
■ 在给MySQL添加新用户时可以这么操作:
create user 'newUser' identified by 'password';grant all privileges on *.* to 'newUser'@'%';flush privileges;
newUser是用户名,password是密码,grant all指把从select到drop,delete等等各种关键字的权限都赋给这个用户,而这个用户可以作用的库和表是*.*(所有库中的所有表),@'%'表名无论这个用户是从什么地方连入的数据库都可以有权限。如果是@'localhost'的话那么只有从本地连入才有权限。flush privileges用于更新系统的权限表。
如此一来新用户就创建完成了。但是在一些情况下,我们仍然无法从mysql的命令行界面登录这个新用户,用dbvis等工具却可以远程连接。网上说了一些添加免密码配置什么的治标不治本。其实是因为mysql.user表中存在几个匿名用户,这几个匿名用户的作用据说是为了保证免密登录的可能,感觉很扯。。总之把他们从user表中删掉之后,再重启下mysqld服务就可以让新创建的用户从mysql命令行界面登录了。:
mysql>delete from mysql.user where user='';mysql>quit;#mysql -u newUser -ppassword:mysql> #登录成功
■ 更改密码时的特殊操作
如果忘记了某个用户的密码,那么可以通过改表的方式来更改密码。但是要注意数据库中的密码存的当然不是明文而是加密过的版本。比如:
update user set password='123456' where user='Frank';#这样是错的!这样存到表中密码字段的内容是123456,是明文,不能发挥作用update user set password=password('123456') where user='Frank';#这样才是对的
改完之后如果无效果记得重启下mysql。
■ 查看一个表本身的信息,比如含有哪些字段,哪些关联关系等通过的是
show create table <表名> 这样来看的。
■ 有外键关联的表不能直接通过drop table <表名> 删除。必须要先去除外键关联。而去除外键关联的操作是:
alter table <表名> drop foreign key <外键名> ; 外键名> 表名>
所谓的外键名可以通过show create table <表名> 来查到。比如这样一行中:
CONSTRAINT `articles_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) articles_ibfk_1就是外键名了。
■ 今天在用SQLAlchemy插入数据的时候,无论如何都报数据过长的1406错误。但是肯定不是真的数据过长了,是字符编码的问题(用英文就可以插入了)。仔细检查了一下之后,发现是数据库的URI中最后加上了参数charset=gbk,然而实际上数据库的编码格式已经被我alter成utf8了。。所以想要不报错就应该注意两者的统一。
■ 查看数据库大小、表大小等数据
这些数据都被维护在information_schema这个数据库中,而数据大小是由data_length字段说明的。所以要查看一个数据库或者一张表的大小可以采取这样的手段:
use information_schema;select concat(round(sum(data_length/1024/1024),2),'MB') as data from tables;/*查看所有数据(全部库的全部表)占用空间大小*/select concat(round(sum(data_length/1024/1024),2),'MB') as data from tables where table_schema='database' and table_name='table';/*根据where子句查看某个特定数据库database和某张特定的表table的占用空间大小*/
■ 数据的备份和还原
在命令行用mysql自带的mysqldump命令就可以实现比较好的数据库(表)的备份和还原。
比如可以mysqldump -hhost -uuser -ppassword database_name > dmpfile.dmp。因为把密码写在明文中,mysql还会提示不安全,在交互界面可以隐去然后输入。
然后我们就得到了一个dmpfile.dmp文件,打开看下其实里面就是SQL语句。
上面这个命令还只是没有任何参数的命令,比较成熟的是:
mysqldump -hhost -uuser -ppassword --skip-opt --skip-comment --complete-insert --add-drop-table db_name > dmpfile.dmp
上面的这几个参数都是显而易见的,其中add-drop-table是在所有建表语句之前增加一个DROP TABLE IF EXISTS,这样就可以直接覆盖环境而不是需要先清库了。
还原数据时,一种方法是先通过字符界面登录到mysql中,选择要覆盖的数据库(如果没有的话就要重新创建一个新数据库了,此时应该注意当前用户对这个新数据库有权限并且新数据库的编码应该和老数据库一致),然后确保要还原的数据都后缀是.sql,然后在数据库中运行命令source /path/to/dmp.sql。然后等运行就好了。运行完成之后可以进去看看情况,有时候中文会遇到乱码。如果中文遇到乱码请确认导出来的.sql文件的编码格式和要导入的数据库的编码格式。如果不确定可以在导出导入命令中体现,比如导出时加上--default-character-set=utf8,导入前在通过mysql命令登录数据库时加上--default-character-set=utf8,再source可以保证编码一致,也就不会乱码了。
需要注意的一个坑:导出来的数据文件中(如果原库中有视图之类的东西的话)是可能含有导出动作时数据库用户的信息的,如果导入新库时使用的用户、库名等和老库不一致,就可能会引起报错。一个解决方案就是修改导出文件中所有老库用户名以及相关信息为新库用户名和相关信息。特别注意导出数据中包含视图的时候,在文件的末尾附近会有很多创建视图的语句(表面上还是被注释着的),此时有个字段DEFINER=xxx这个xxx是导出时用的用户名,而如果导入时用的用户名不一样了,记得要把这个用户名给改过来。
另一个坑:当选用--skip-opts参数之后,其实是选择禁用了一批参数,这些参数大致包括--add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, --disable-keys。其中值得一提的是create-options,不带此参数导出,表中的自增字段会无法成功生效。即导出的SQL的建表语句中没有AUTO_INCREMENT的声明的。另外extended-insert和complete-insert是反义词,前者表示插入数据时的insert语句是一张表只有一句,数据以多个元组的列表的形式插入。而complete-insert参数导出的SQL中insert语句是一行一句。因此后者导出的文件会大很多,而且插入速度会慢一点。不过前者比较消耗数据库性能,两者需要权衡。
■ mysql用户的权限查看
SHOW GRANTS FOR root@'%';
■ mysql新建的用户死活无法登录
按照上面的流程,新建了一个数据库,新建一个用户并且给用户授权了这个数据库的操作权限,而且还是username@'%'的授权。
经过这样操作在我另一台机器上创建出来的用户已经可以正常使用数据库了,但是这台上的死活无法从localhost登录数据库,,试错了好久,并且去网上找了一些答案之后发现了问题原因。在mysql.user表中,存在一些user或者password为空的所谓“匿名用户的存在” ,应该就是匿名用户带来的障碍(虽然不知道为什么匿名用户会导致正常用户无法登录),总之删光这些匿名用户就好了:
delete from mysql.user where user='' or password='';之后别忘了再flush privileges一下。
■ mysql的分页查询以及性能小优化
众所周知mysql可以通过limit关键字进行指定range的分页查询。语法其实是这样的:
SELECT * FROM TABLE LIMIT [START,]OFFSET;
默认的START是0,这个START其实是index,0代表第一行数据。OFFSET是必须有的,指出了从START那个index起的OFFSET条数据(包括STARTindex那条本身)。这也就是说limit 1;选择的就是只有第一条数据,limit 2;选择的是第一条和第二条数据,limit 10000,20;是选取了第10000条到第10019行的数据。
● 关于性能:
分页查询时,可以通过实验得知,越是大的START值查询起来越是慢。比如:
SELECT * FROM EVENTS LIMIT 10000,20;/*用时0.2s*/SELECT * FROM EVENTS LIMIT 1000000,20;/*用时 3.36s*/
虽说现在数据库都有优化了,但是还是有必要了解下这种简单的优化是怎么手动做的。优化的基础是走索引更快这个点。主键eventid是有索引的,所以select eventid from events limit 1000000,20;和10000,20的用时差别并不大。基于这个想法可以利用一个子查询来做:
SELECT * FROM EVENTS WHERE eventid >= (SELECT eventid FROM EVENTS LIMIT 1000000,1) LIMIT 20;
子查询先定位一个主键,然后主键是有序增的,所以基于这个主键界限再limit就快很多了。
■ sql插入数据中含有单引号
SQL中如果插入字符串中含有单引号,此时应该将单引号写两个作为转义。。意想不到的转义方法:
INSERT INTO my_table VALUES ('10001','Let's Go') /*错误*/INSERT INTO my_table VALUES ('10001','Let\'s Go') /*错误*/INSERT INTO my_table VALUES ('10001','Let''s Go') /*正确*/
■ 表结构查询
如果只是想看下表结构长什么样,那么desc table_name或者show create table table_name这样就可以满足需求了。
如果需要将表结构作为数据库数据的一部分,查看具有良好结构的数据的话那么可以采用下面的方法:
所有数据库本身相关的信息都存放在了information_schema库中。比如之前提到过的查询表名,表内数据量的可以通过information_schema.tables查看。
而表结构其实是字段层面的信息,所以在information_schema.columns表中查看。
select * from information_schema.columns where table_schema='database_name' and table_name='table_name'/*这句SQL就可以查到database_name库中table_name表的所有字段信息了*/
■ 将一条记录从一张表转移到另一张表
如果两张表结构一样,可以简单地;
INSERT INTO 表2 SELECT * FROM 表1
如果两张表的结构不太一样,那么需要指定哪几个列需要转移
INSERT INTO 表2 (COL1,COL2,COL3) SELECT (COL1,COL2,COL3) FROM 表2
几个表混合组合数据可以如下:
INSERT INTO 表3 (COL1,COL2,COL3) VALUES ((SELECT COL1 FROM 表1),(SELECT COL2 FROM 表2),(SELECT COL3 FROM 表2))
■ mysqldump由于版本不对无法备份
使用mysqldump的时候出现了类似于
mysqldump: Couldn't execute 'SET OPTION SQL_QUOTE_SHOW_CREATE=1': You have an error in your SQL syntax; check the manual
的错误。出现这个错的主要原因是因为作为客户端的mysqldump和服务端的mysql版本差距较大,比如我的场合中,mysqldump的版本还是5.0.94而服务端已经是5.6了。
经其他主机的客户端试验,发现只要客户端版本达到5.1.72即可使用。但问题在于,这台服务器还是centos5,阿里云没有yum源使用了。而且由于没有开通外网,第三方源也用不了。所以只能想办法获得到mysql官方提供的离线安装方式如rpm包等。
下载地址:https://downloads.mysql.com/archives/community/ 在这个连接中选择相关的系统类型和mysql版本。比如这选mysql 5.1.72(5.1大版本维护的最终小版本)还有redhat-release,64bit系统。下面就会有mysql各种组件的rpm包下载链接了。重点关注的是clilent utilities这个包。
下载这个包之后放到服务器上rpm -ivh安装。发现报错文件冲突。一开始想能不能保留原文件,把新客户端内容装到独立的目录中去,于是尝试加上了--prefix参数。但是发现不行,mysql客户端的安装一定要装在规定目录下…于是只能rpm -e把原先的mysql客户端删掉。(注意,一个服务器上很可能除了客户端还安装有服务端,兼容包等多个mysql相关组件,注意只删除客户端组件。比如rpm -ql某个包中有类似于/usr/bin/mysql,/usr/bin/mysqldump这种东西的话那就是客户端组件了。)然后安装就可以了。