| cp's profile我的资料库PhotosBlogLists | Help |
|
|
May 25 Mysql怎么样支持中文查询?Q: 我在写一个查询条件时的问题如下: 如我想写一个字段中包含“李”字的所有记录 $str="李"; select * from table where field like '%$str%' ; 显示的记录中除了包含”李”字的记录,还有不包含“李”字的记录。为什么? A: 在MySQL中,进行中文排序和查找的时候,对汉字的排序和查找结果是错误的。这种情况在MySQL的很多版本中都存在。如果这个问题不解决,那么MySQL将无法实际处理中文。 出现这个问题的原因是:MySQL在查询字符串时是大小写不敏感的,在编绎MySQL时一般以ISO-8859字符集作为默认的字符集,因此在比较过程中中文编码字符大小写转换造成了这种现象。 方法一: 解决方法是对于包含中文的字段加上"binary"属性,使之作为二进制比较,例如将"name char(10)"改成"name char(10)binary"。 方法二: 如果你使用源码编译MySQL,可以编译MySQL时使用--with--charset=gbk 参数,这样MySQL就会直接支持中文查找和排序了。 方法三: 可以使用 Mysql 的 locate 函数来判断。以上述问题为例,使用方法为: SELECT * FROM table WHERE locate(field,'李') > 0; 本站使用的就是这种方法,感觉还不错。:P MYSQL服务维护笔记 本文介绍作者使用MYSQL服务的一些经验,主要从以下几个方面讲解MYSQL服务规划设计: 1 MYSQL服务的安装/配置的通用性; 2 系统的升级和数据迁移方便性; 3 备份和系统快速恢复; MYSQL服务器的规划 为了以后维护,升级备份的方便和数据的安全性,最好将MYSQL程序文件和数据分别安装在“不同的硬件”上。 / /usr <== 操作系统 }==> 硬盘1 /home/mysql <== mysql应用程序 ... /data/app_1/ <== 应用数据和脚本 }==> 硬盘2 /data/app_2/ /data/app_3/ mysql服务的安装和服务的启动: MYSQL一般使用当前STABLE的版本,尽量不使用--with-charset=选项,我感觉with-charset只在按字母排序的时候才有用,这些选项会对数据的迁移带来很多麻烦。 configure --prefix=/home/mysql make make install 服务的启动和停止 1 复制缺省的mysql/var/mysql到 /data/app_1/目录下, 2 MYSQLD的启动脚本:start_mysql.sh #!/bin/sh rundir=`dirname ""` echo "$rundir" /home/mysql/bin/safe_mysqld --user=mysql --pid-file="$rundir"/mysql.pid --datadir="$rundir"/var "$@"\ -O max_connections=500 -O wait_timeout=600 -O key_buffer=32M --port=3402 --socket="$rundir"/mysql.sock & 注释: --pid-file="$rundir"/mysql.pid --socket="$rundir"/mysql.sock --datadir="$rundir"/var 目的都是将相应数据和应用临时文件放在一起; -O 后面一般是服务器启动全局变量优化参数,有时候需要根据具体应用调整; --port: 不同的应用使用PORT参数分布到不同的服务上去,一个服务可以提供的连接数一般是MYSQL服务的主要瓶颈; 修改不同的服务到不同的端口后,在rc.local文件中加入: /data/app_1/start_mysql.sh /data/app_2/start_mysql.sh /data/app_3/start_mysql.sh 注意:必须写全路径 3 MYSQLD的停止脚本:stop_mysql.sh #!/bin/sh rundir=`dirname ""` echo "$rundir" /home/mysql/bin/mysqladmin -u mysql -S"$rundir"/mysql.sock shutdown 使用这个脚本的好处在于: 1 多个服务启动:只需要修改脚本中的--port=参数。单个目录下的数据和服务脚本都是可以独立打包的。 2 所有服务相应文件都位于/data/app_1/目录下:比如:mysql.pid mysql.sock,当一台服务器上启动多个服务时,多个服务不会互相影响。但都放到缺省的/tmp/下则有可能被其他应用误删。 3 当硬盘1出问题以后,直接将硬盘2放到一台装好MYSQL的服务器上就可以立刻恢复服务(如果放到my.cnf里则还需要备份相应的配置文件)。 服务启动后/data/app_1/下相应的文件和目录分布如下: /data/app_1/ start_mysql.sh 服务启动脚本 stop_mysql.sh 服务停止脚本 mysql.pid 服务的进程ID mysql.sock 服务的SOCK var/ 数据区 mysql/ 用户库 app_1_db_1/ 应用库 app_2_db_2/ ... /data/app_2/ ... 查看所有的应用进程ID: cat /data/*/mysql.pid 查看所有数据库的错误日志: cat /data/*/var/*.err 个人建议:MYSQL的主要瓶颈在PORT的连接数上,因此,将表结构优化好以后,相应单个MYSQL服务的CPU占用仍然在10%以上,就要考虑将服务拆分到多个PORT上运行了。 服务的备份 尽量使用MYSQL DUMP而不是直接备份数据文件,以下是一个按weekday将数据轮循备份的脚本:备份的间隔和周期可以根据备份的需求确定 /home/mysql/bin/mysqldump -S/data/app_1/mysql.sock -umysql db_name | gzip -f>/path/to/backup/db_name.`data +%w`.dump.gz 因此写在CRONTAB中一般是: * 6 * * * /home/mysql/bin/mysqldump -S/data/app_1/mysql.sock -umysql db_name | gzip -f>/path/to/backup/db_name.`data +\%w`.dump.gz 注意: 1 在crontab中'%'需要转义成'\%' 2 根据日志统计,应用负载最低的时候一般是在早上6点 先备份在本地然后传到远程的备份服务器上,或者直接建立一个数据库备份帐号,直接在远程的服务器上备份,远程备份只需要将以上脚本中的-S /path/to/msyql.sock改成-h IP.ADDRESS即可。 数据的恢复和系统的升级 日常维护和数据迁移:在数据盘没有被破坏的情况下 硬盘一般是系统中寿命最低的硬件。而系统(包括操作系统和MYSQL应用)的升级和硬件升级,都会遇到数据迁移的问题。 只要数据不变,先装好服务器,然后直接将数据盘(硬盘2)安装上,只需要将启动脚本重新加入到rc.local文件中,系统就算是很好的恢复了。 灾难恢复:数据本身被破坏的情况下 确定破坏的时间点,然后从备份数据中恢复。 应用的设计要点 非用数据库不可吗? 数据库的确可以简化很多应用的结构设计,但本身也是一个系统资源消耗比较大的应用。所以很多应用如果没有很高的实时统计需求的话,完全可以先记录到文件日志中,定期的导入到数据库中做后续统计分析。如果还是需要记录2维表结构,结构足够简单的话可以使用DBM结构。即使需要使用数据库的,应用如果没有太复杂的数据完整性需求的化,完全可以不使用那些支持外键的商业数据库, 数据库服务的主要瓶颈:单个服务的连接数 对于一个应用来说,如果数据库表结构的设计能够按照数据库原理的范式来设计的话,并且已经使用了最新版本的MYSQL,并且按照比较优化的方式运行了,那么最后的主要瓶颈一般在于单个服务的连接数,即使一个数据库可以支持并发500个连接,最好也不要把应用用到这个地步,因为并发连接数过多数据库服务本身用于调度的线程的开销也会非常大了。所以如果应用允许的话:让一台机器多跑几个MYSQL服务分担。将服务均衡的规划到多个MYSQL服务端口上:比如app_1 ==> 3301 app_2 ==> 3302...app_9 ==> 3309。一个1G内存的机器跑上10个MYSQL是很正常的。让10个MYSQLD承担1000个并发连接效率要比让2个MYSQLD承担1000个效率高的多。当然,这样也会带来一些应用编程上的复杂度; 使用单独的数据库服务器(不要和前台WEB服务抢内存),MYSQL拥有更多的内存就可能能有效的进行结果集的缓存; 应用尽量使用PCONNECT和polling机制,用于节省MYSQL服务建立连接的开销; 表的横向拆分:让最常被访问的10%的数据放在一个小表里,90%的历史数据放在一个归档表里,数据中间通过定期“搬家”和定期删除无效数据来节省。这样对于应用来说总是在10%数据中进行选择,比较有利于数据的缓存,不要指望MYSQL中对单表记录数在10万级以上还有比较高的效率。 表的纵向拆分(过渡范化):将所有的定长字段(char, int等)放在一个表里,所有的变长字段(varchar,text,blob等)放在另外一个表里,2个表之间通过主键关联,这样,定长字段表可以得到很大的优化(甚至可以使用HEAP表类型,数据完全在内存中存取),这里也说明另外一个原则,对于我们来说,尽量使用定长字段可以通过空间的损失换取访问效率的提高。MYSQL之所以支持多种表类型,实际上是针对不同应用提供了不同的优化方式; 仔细的检查应用的索引设计,甚至在服务启动中加入 --log-slow-queries[=file]用于跟踪分析应用瓶颈。 mysql中的临时表 当工作在非常大的表上时,你可能偶尔需要运行很多查询获得一个大量数据的小的子集,不是对整个表运行这些查询,而是让MySQL每次找出所需的少数记录,将记录选择到一个临时表可能更快 些,然后多这些表运行查询。 创建临时表很容易,给正常的CREATE TABLE语句加上TEMPORARY关键字: CREATE TEMPORARY TABLE tmp_table ( name VARCHAR(10) NOT NULL, value INTEGER NOT NULL ) 临时表将在你连接MySQL期间存在。当你断开时,MySQL将自动删除表并释放所用的空间。当然你可以在仍然连接的时候删除表并释放空间。 DROP TABLE tmp_table 如果在你创建名为tmp_table临时表时名为tmp_table的表在数据库中已经存在,临时表将有必要屏蔽(隐藏)非临时表tmp_table。 如果你声明临时表是一个HEAP表,MySQL也允许你指定在内存中创建它: CREATE TEMPORARY TABLE tmp_table ( name VARCHAR(10) NOT NULL, value INTEGER NOT NULL ) TYPE = HEAP 因为HEAP表存储在内存中,你对它运行的查询可能比磁盘上的临时表快些。然而,HEAP表与一般的表有些不同,且有自身的限制。详见MySQL参考手册。 正如前面的建议,你应该测试临时表看看它们是否真的比对大量数据库运行查询快。如果数据很好地索引,临时表可能一点不快。 如何将图片储存在MySQL数据库里 如果你想把二进制的数据,比如说图片文件和HTML文件,直接保存在你的MySQL数据库,那么这篇文章就是为你而写的!我将告诉你怎样通过HTML表单来储存这些文件,怎样访问和使用这些文件。 一、本文概述 本文的主要内容如下: * 在MySQL中建立一个新的数据库 * 一个怎样储存文件的例子程序 * 一个怎样访问文件的例子程序 二、在MySQL中建立一个新的database 首先,你必须在你的MySQL中建立一个新的数据库,我们将会把那些二进制文件储存在这个数据库里。在例子中我会使用下列结构,为了建立数据库,你必须做下列步骤: 1. 进入MySQL控制器 2. 输入命令"create database binary_data;" 3. 输入命令"use binary_data;" 输入如下命令: "CREATE TABLE binary_data ( id INT(4) NOT NULL AUTO_INCREMENT PRIMARY KEY,description CHAR(50), bin_data LONGBLOB, filename CHAR(50), filesize CHAR(50), filetype CHAR(50));" (不能断行) 如果没有意外,数据库 和 表 应该建立好了。 三、一个怎样储存文件的例子程序 用这个例子你可以通过Html表单将文件传输到数据库中。 store.php3 // store.php3 - by Florian Dittmer <?php // 如果提交了表单,代码将被执行: if ($submit) { // 连接到数据库 // (你可能需要调整主机名,用户名和密码) MYSQL_CONNECT( "localhost", "root", "password"); MySQL_select_db( "binary_data"); $data = addslashes(fread(fopen($form_data, "r"), filesize($form_data))); $result=MYSQL_QUERY( "INSERT INTO binary_data (description,bin_data,filename,filesize,filetype)VALUES ('$form_description','$data','$form_data_name','$form_data_size','$form_data_type')"); $id= MySQL_insert_id(); print "This file has the following Database ID: $id"; MYSQL_CLOSE(); } else { // 否则显示储存新数据的表单 @MySQL_select_db( "binary_data"); $query = "select bin_data,filetype from binary_data where id=$id"; $result = @MYSQL_QUERY($query); $data = @MYSQL_RESULT($result,0, "bin_data"); $type = @MYSQL_RESULT($result,0, "filetype"); Header( "Content-type: $type"); echo $data; }; ?> 程序必须知道要访问那个文件, 你必须将ID作为一个参数。 例如: 一个文件在数据库中的ID为2. 你可以这样调用它: getdata.php3?id=2 如果你将图片储存在数据库里, 你可以向调用图片一样调用它。 Example: 一个图片文件在数据库中的ID为3. 你可以这样调用它: 五、怎样储存大于1MB的文件 如果你想储存大于1MB的文件,你必须对你的程序、PHP设置、SQL设置进行许多修改。 下面几条也许可以帮助你储存小于24MB的文件: 1) 修改 store.php3,将 MAX_FILE_SIZE 的值改成 24000000。 2) 修改你的PHP设置,在一般情况下,PHP只允许小于2MB的文件,你必须将max_filesize(在php.ini中)的值改成24000000 3) 去掉MYSQL的数据包大小限制,在一般情况下 MYSQL 小于1 MB的数据包。 4) 你必须用以下参数重启你的MYSQL :/usr/local/bin/safe_MySQLd -O key_buffer=16M -O table_cache=128 -O sort_buffer=4M -O record_buffer=1M -O max_allowed_packet=24M 5) 如果仍然出错:可能是超时错误,如果你通过一个很慢的连接来储存一个很大的文件,PHP缺省的时间限制为30秒。你可以将max_execution_time(在php.ini中)的值改为-1 。 加固你的MySQL前言 MySQL已经成为当前网络中使用最多的数据库之一,特别是在Web应用上,它占据了中小型应用的绝对优势。这一切都源于它的小巧易用、它的安全有效、它的开放式许可、它的多平台,更主要的是它与三大Web语言之——PHP的完美结合。 但不幸的是,一个缺省安全的MySQL,会因为root密码为空及程序漏洞导致被溢出,使得安装MySQL的服务器成为被经常攻击的对象。更严重的是,被攻击之后数据库往往遭破坏,造成灾难性的后果。下面将进入为了保护数据而进行的保卫战中。 环境要求 1.系统环境 一台Red Hat 9.0自定义安装的服务器,系统安装了GCC及一些其它要求的软件包,比如Apache、PHP等。安装完系统后的第一件事就是升级系统的软件包。作为Web服务器,系统接受PHP脚本的请求,PHP则使用下面将要安装的MySQL数据库作为动态发布的接触。 分区情况的要求和一般系统差不多,惟一不同之处在于后面建立的/chroot与/tmp要求在同一个分区上。 2.安全要求 (1)MySQL运行在一个独立的(Chroot)环境下; (2)mysqld进程运行于一个独立的用户/用户组下, 此用户和用户组没有根目录,没有shell,也不能用于其它程序; (3)修改MySQL的root帐号,并使用一个复杂的密码; (4)只允许本地连接MySQL,启动MySQL时网络连接被禁止掉; (5)保证连接MySQL的nobody帐号登陆被禁止; (6)删除test数据库。 安装MySQL 1.安装准备 安装MySQL之前,按照上述安全要求需要创建一个用于启动MySQL的用户和组。 #groupadd mysql #useradd mysql -c "start mysqld's account" -d /dev/null -g mysql -s /sbin/nologin 2.编译和安装 下载MySQL源代码包: #wget http://mysql.he.net/Downloads/MySQL-4.0/mysql-4.0.16.tar.gz 解压缩: #tar -zxvf mysql-4.0.16.tar.gz 一般把MySQL安装在/usr/local/mysql下,如果有特殊要求,也可自行调整。不过这样做意义不大,因为后面将Chrooting,到时只是使用这里的客户工具而已,比如mysql,mysqladmin,mysqldump等。下面就开始编译安装吧。 #./configure --prefix=/usr/local/mysql \ --with-mysqld-user=mysql \ --with-unix-socket-path=/tmp/mysql.sock \ --with-mysqld-ldflags=-all-static #make && make install #strip /usr/local/mysql/libexec/mysqld #scripts/mysql_install_db #chown -R root /usr/local/mysql #chown -R mysql /usr/local/mysql/var #chgrp -R mysql /usr/local/mysql 上面各步骤的具体作用在MySQL手册里已有介绍,惟一需要解释、和一般步骤不同的地方在于--with-mysqld-ldflags=-all-static。因为需要用到Chroot环境,而MySQL本身连接成静态后就无需再创建一些库环境了。 3.配置与启动 MySQL的配置文件需要手工选择、拷贝几个模板文件中的一个到/etc下,这几个模板文件位于源文件的support-files目录,一共4个:small、medium、large、huge。 #cp support-files/my-medium.cnf /etc/my.cnf #chown root:sys /etc/my.cnf #chmod 644 /etc/my.cnf 启动MySQL,注意使用用户为mysql: #/usr/local/mysq/bin/mysqld_safe --user=mysql & 4.测试 为了测试安装的程序是否正确及MySQL是否已经启动正常,最好的办法就是用MySQL客户端来连接数据库。 #/usr/local/mysql/bin/mysql [root@ftp bin]# mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 687 to server version: 3.23.58 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> mysql> show databases; +--------------+ | Database | +--------------+ | mysql | | test | +--------------+ 2 rows in set (0.00 sec) mysql>quit 连接成功,可以关闭数据库: #/usr/local/mysql/bin/mysqladmin -uroot shutdown 如果连接失败则需要仔细分析出错原因: #more /usr/local/mysql/var/`hostname`.err Chrooting 1.Chrooting环境 Chroot是Unix/类Unix的一种手段,它的建立会将其与主系统几乎完全隔离,也就是说,一旦遭到什么问题,也不会危及到正在运行的主系统。这是一个非常有效的办法,特别是在配置网络服务程序的时候。 2.Chroot的准确工作 首先,应当建立如图1示目录结构: 图1 目录结构 #mkdir -p /chroot/mysql/dev #mkdir -p /chroot/mysql/etc #mkdir -p /chroot/mysql/tmp #mkdir -p /chroot/mysql/var/tmp #mkdir -p /chroot/mysql/usr/local/mysql/libexec #mkdir -p /chroot/mysql/usr/local/mysql/share/mysql/english 然后设定目录权限: #chown -R root:sys /chroot/mysql #chmod -R 755 /chroot/mysql #chmod 1777 /chroot/mysql/tmp 3.拷贝mysql下的程序和文件到chroot下 #cp -p /usr/local/mysql/libexec/mysqld /chroot/mysql/usr/local/mysql/libexec/ #cp -p /usr/local/mysql/share/mysql/english/errmsg.sys /chroot/mysql/usr/local/mysql/share/mysql/english/ #cp -p /etc/hosts /chroot/mysql/etc/ #cp -p /etc/host.conf /chroot/mysql/etc/ #cp -p /etc/resolv.conf /chroot/mysql/etc/ #cp -p /etc/group /chroot/mysql/etc/ #cp -p /etc/passwd /chroot/mysql/etc/passwd #cp -p /etc/my.cnf /chroot/mysql/etc/ 4.编辑chroot下的passwd文件和group文件 #vi /chroot/etc/passwd 删除除了mysql、root、sys的所有行 #vi /chroot/etc/group 删除除了mysql、root的所有行 5.创建特殊的设备文件/dev/null 参照系统的样子做即可: #ls -al /dev/null crw-rw-rw- 1 root root 1, 3 Jan 30 2003 /dev/null #mknod /chroot/mysql/dev/null c 1 3 #chown root:root /chroot/mysql/dev/null #chmod 666 /chroot/mysql/dev/null 6.拷贝mysql的数据库文件到chroot下 #cp -R /usr/local/mysql/var/ /chroot/mysql/usr/local/mysql/var #chown -R mysql:mysql /chroot/mysql/usr/local/mysql/var 7.安装chrootuid程序 下载chrootuid,然后RPM安装即可。 http://rpm.pbone.net/index.php3/stat/4/idpl/355932/com/ chrootuid-1.3-alt2.i586.rpm.html 8.测试Chroot环境下的MySQL配置 #chrootuid /chroot/mysql mysql /usr/local/mysql/libexec/mysqld & 如果失败请注意chroot目录下面的权限问题。 9.测试连接chroot下的MySQL #/usr/local/mysql/bin/mysql --socket=/chroot/mysql/tmp/mysql.sock .............. mysql>show databases; mysql>create database wgh; mysql>quit; #ls -al /chroot/mysql/var/ ............... 配置服务器 为了更加安全地使用MySQL,需要对MySQL的数据库进行安全配置;并且由于Chroot的原因,配置文件也会有所不同。 1.关闭远程连接 首先,应该关闭3306端口,这是MySQL的默认监听端口。由于此处MySQL只服务于本地脚本,所以不需要远程连接。尽管MySQL内建的安全机制很严格,但监听一个TCP端口仍然是危险的行为,因为如果MySQL程序本身有问题,那么未授权的访问完全可以绕过MySQL的内建安全机制。关闭网络监听的方法很简单,在/chroot/mysql/etc/my.cnf文件中的[mysqld]部分,去掉#skip-networking前面的“#”即可。 关闭了网络,本地程序如何连接MySQL数据库呢?本地程序可以通过mysql.sock来连接,速度比网络连接更快。后文将提到关于mysql.sock的具体情况。 MySQL的备份通常使用SSH来执行! 2.禁止MySQL导入本地文件 下面,将禁止MySQL中用“LOAD DATA LOCAL INFILE”命令。这个命令会利用MySQL把本地文件读到数据库中,然后用户就可以非法获取敏感信息了。网络上流传的一些攻击方法中就有用它的,它也是很多新发现的SQL Injection攻击利用的手段! 为了禁止上述命令,在/chroot/mysql/etc/my.cnf文件的[mysqld]部分加入: set-variable=local-infile=0 为了管理方便,一般在系统中的MySQL管理命令如mysql,mysqladmin,mysqldump等,使用的都是系统的/etc/my.cnf文件。如果要连接,它会寻找/tmp/mysql.sock文件来试图连接MySQL服务器,但是这里要连接的是chroot下的MySQL服务器,解决办法有两个:一个是在管理命令后面加入--socket=/chroot/mysql/tmp/mysql.sock。例如: #/usr/local/mysql/bin/mysql -root -p --socket=/chroot/mysql/tmp/mysql.sock 第二个就是在/etc/my.cnf的[client]部分加入socket=/chroot/mysql/tmp/mysql.sock。显然,第二个方法方便多了。 3.修改MySQL的root用户ID和密码 #chrootuid /chroot/mysql mysql /usr/local/mysql/libexec/mysqld & #/usr/local/mysql/bin/mysql -uroot ............... mysql>SET PASSWORD FOR root@localhost=PASSWORD('new_password'); 尽量养成在mysql下输入密码的习惯,因为Shell下面输入的时候可能会被其它人看见。 mysql>use mysql; mysql>update user set user="wghgreat" where user="root"; mysql>select Host,User,Password,Select_priv,Grant_priv from user; mysql>delete from user where user=''; mysql>delete from user where password=''; mysql>delete from user where host='%'; mysql>Drop database test; mysql>flush privileges; mysql>quit; 修改为一个不容易猜的ID 4.删除历史命令记录 这些历史文件包括~/.bash_history、~/.mysql_history等。如果打开它们,你会大吃一惊,怎么居然有一些明文的密码在这里?! #cat /dev/null > ~/.bash_history #cat /dev/null > ~/.mysql_history PHP和MySQL通信 默认情况下,PHP会通过/tmp/mysql.sock来和MySQL通信,但这里的一个大问题是MySQL生成的根本不是它,而是/chroot/mysql/tmp/mysql.sock。解决的办法就是做一个连接: #ln /chroot/mysql/tmp/mysql.sock /tmp/mysql.sock 注意:由于hard links不能在文件系统的分区之间做,所以该处的连接必须位于同一分区内部。 自启动配置 自启动配置前先提示一点:即用于PHP的数据库需要用一个新建的帐号,其上有数据库权限设置,比如FILE、GRANT、ACTER、SHOW DATABASE、RELOAD、SHUTDOWN、PROCESS、SUPER等。 自启动脚本示例: #!/bin/sh CHROOT_MYSQL=/chroot/mysql SOCKET=/tmp/mysql.sock MYSQLD=/usr/local/mysql/libexec/mysqld PIDFILE=/usr/local/mysql/var/`hostname`.pid CHROOTUID=/usr/bin/chrootuid echo -n " mysql" case "" in start) rm -rf $ nohup $ ${CHROOT_MYSQL} mysql $ >/dev/null 2>&1 & sleep 5 && ln ${CHROOT_MYSQL}/$ $ ;; stop) kill `cat ${CHROOT_MYSQL}/$` rm -rf ${CHROOT_MYSQL}/$ ;; *) echo "" echo "Usage: `basename ` {start|stop}" >&2 exit 64 ;; esac exit 0 文件位于/etc/rc.d/init.d下,名为mysqld,注意要可执行。 #chmod +x /etc/rc.d/init.d/mysqld #ln -s /etc/rc.d/init.d/mysql /etc/rc3.d/S90mysql #ln -s /etc/rc.d/init.d/mysql /etc/rc0.d/K20mysql 结论:尽管我们不能做到100%的安全,但是这些措施可以保护我们的系统更加安全! MySQL索引分析和优化一、什么是索引?
索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。表里面的记录数量越多,这个操作的代价就越高。如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置。如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍。 假设我们创建了一个名为people的表: CREATE TABLE people ( peopleid SMALLINT NOT NULL, name CHAR(50) NOT NULL ); 然后,我们完全随机把1000个不同name值插入到people表。下图显示了people表所在数据文件的一小部分:
可以看到,在数据文件中name列没有任何明确的次序。如果我们创建了name列的索引,MySQL将在索引中排序name列: 对于索引中的每一项,MySQL在内部为它保存一个数据文件中实际记录所在位置的“指针”。因此,如果我们要查找name等于“Mike”记录的peopleid(SQL命令为“SELECT peopleid FROM people WHERE name='Mike';”),MySQL能够在name的索引中查找“Mike”值,然后直接转到数据文件中相应的行,准确地返回该行的peopleid(999)。在这个过程中,MySQL只需处理一个行就可以返回结果。如果没有“name”列的索引,MySQL要扫描数据文件中的所有记录,即1000个记录!显然,需要MySQL处理的记录数量越少,则它完成任务的速度就越快。 二、索引的类型 MySQL提供多种索引类型供选择: 普通索引这是最基本的索引类型,而且它没有唯一性之类的限制。普通索引可以通过以下几种方式创建: 创建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表); 修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表); 创建表的时候指定索引,例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) ); 唯一性索引 这种索引和前面的“普通索引”基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一。唯一性索引可以用以下几种方式创建: 创建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表); 修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表); 创建表的时候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表) ); 主键 主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”。如果你曾经用过AUTO_INCREMENT类型的列,你可能已经熟悉主键之类的概念了。主键一般在创建表的时候指定,例如“CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); ”。但是,我们也可以通过修改表的方式加入主键,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每个表只能有一个主键。 全文索引 MySQL从3.23.23版开始支持全文索引和全文检索。在MySQL中,全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者TEXT类型的列上创建。它可以通过CREATE TABLE命令创建,也可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集,通过ALTER TABLE(或者CREATE INDEX)命令创建全文索引要比把记录插入带有全文索引的空表更快。本文下面的讨论不再涉及全文索引,要了解更多信息,请参见MySQL documentation。 三、单列索引与多列索引 索引可以是单列索引,也可以是多列索引。下面我们通过具体的例子来说明这两种索引的区别。假设有这样一个people表: 这个数据片段中有四个名字为“Mikes”的人(其中两个姓Sullivans,两个姓McConnells),有两个年龄为17岁的人,还有一个名字与众不同的Joe Smith。 这个表的主要用途是根据指定的用户姓、名以及年龄返回相应的peopleid。例如,我们可能需要查找姓名为Mike Sullivan、年龄17岁用户的peopleid(SQL命令为SELECT peopleid FROM people WHERE firstname='Mike' AND lastname='Sullivan' AND age=17;)。由于我们不想让MySQL每次执行查询就去扫描整个表,这里需要考虑运用索引。 首先,我们可以考虑在单个列上创建索引,比如firstname、lastname或者age列。如果我们创建firstname列的索引(ALTER TABLE people ADD INDEX firstname (firstname);),MySQL将通过这个索引迅速把搜索范围限制到那些firstname='Mike'的记录,然后再在这个“中间结果集”上进行其他条件的搜索:它首先排除那些lastname不等于“Sullivan”的记录,然后排除那些age不等于17的记录。当记录满足所有搜索条件之后,MySQL就返回最终的搜索结果。 由于建立了firstname列的索引,与执行表的完全扫描相比,MySQL的效率提高了很多,但我们要求MySQL扫描的记录数量仍旧远远超过了实际所需要的。虽然我们可以删除firstname列上的索引,再创建lastname或者age列的索引,但总地看来,不论在哪个列上创建索引搜索效率仍旧相似。 为了提高搜索效率,我们需要考虑运用多列索引。如果为firstname、lastname和age这三个列创建一个多列索引,MySQL只需一次检索就能够找出正确的结果!下面是创建这个多列索引的SQL命令: ALTER TABLE people ADD INDEX fname_lname_age (firstname,lastname,age); 由于索引文件以B-树格式保存,MySQL能够立即转到合适的firstname,然后再转到合适的lastname,最后转到合适的age。在没有扫描数据文件任何一个记录的情况下,MySQL就正确地找出了搜索的目标记录! 那么,如果在firstname、lastname、age这三个列上分别创建单列索引,效果是否和创建一个firstname、lastname、age的多列索引一样呢?答案是否定的,两者完全不同。当我们执行查询的时候,MySQL只能使用一个索引。如果你有三个单列的索引,MySQL会试图选择一个限制最严格的索引。但是,即使是限制最严格的单列索引,它的限制能力也肯定远远低于firstname、lastname、age这三个列上的多列索引。 四、最左前缀 多列索引还有另外一个优点,它通过称为最左前缀(Leftmost Prefixing)的概念体现出来。继续考虑前面的例子,现在我们有一个firstname、lastname、age列上的多列索引,我们称这个索引为fname_lname_age。当搜索条件是以下各种列的组合时,MySQL将使用fname_lname_age索引: firstname,lastname,age firstname,lastname firstname从另一方面理解,它相当于我们创建了(firstname,lastname,age)、(firstname,lastname)以及(firstname)这些列组合上的索引。下面这些查询都能够使用这个fname_lname_age索引: MySQL文档找到有关该命令的更多说明。下面是一个例子: table type possible_keys key key_len ref rows Extra people ref fname_lname_age fname_lname_age 102 const,const,const 1 Where used下面我们就来看看这个EXPLAIN分析结果的含义。
“对于每一种与另一个表中记录的组合,MySQL将从当前的表读取所有带有匹配索引值的记录。如果连接操作只使用键的最左前缀,或者如果键不是UNIQUE或PRIMARY KEY类型(换句话说,如果连接操作不能根据键值选择出唯一行),则MySQL使用ref连接类型。如果连接操作所用的键只匹配少量的记录,则ref是一种好的连接类型。” 在本例中,由于索引不是UNIQUE类型,ref是我们能够得到的最好连接类型。 如果EXPLAIN显示连接类型是“ALL”,而且你并不想从表里面选择出大多数记录,那么MySQL的操作效率将非常低,因为它要扫描整个表。你可以加入更多的索引来解决这个问题。预知更多信息,请参见MySQL的手册说明。 possible_keys: 可能可以利用的索引的名字。这里的索引名字是创建索引时指定的索引昵称;如果索引没有昵称,则默认显示的是索引中第一个列的名字(在本例中,它是“firstname”)。默认索引名字的含义往往不是很明显。 Key: 它显示了MySQL实际使用的索引的名字。如果它为空(或NULL),则MySQL不使用索引。 key_len: 索引中被使用部分的长度,以字节计。在本例中,key_len是102,其中firstname占50字节,lastname占50字节,age占2字节。如果MySQL只使用索引中的firstname部分,则key_len将是50。 ref: 它显示的是列的名字(或单词“const”),MySQL将根据这些列来选择行。在本例中,MySQL根据三个常量选择行。 rows: MySQL所认为的它在找到正确的结果之前必须扫描的记录数。显然,这里最理想的数字就是1。 Extra: 这里可能出现许多不同的选项,其中大多数将对查询产生负面影响。在本例中,MySQL只是提醒我们它将用WHERE子句限制搜索结果集。 七、索引的缺点 到目前为止,我们讨论的都是索引的优点。事实上,索引也是有缺点的。 首先,索引要占用磁盘空间。通常情况下,这个问题不是很突出。但是,如果你创建每一种可能列组合的索引,索引文件体积的增长速度将远远超过数据文件。如果你有一个很大的表,索引文件的大小可能达到操作系统允许的最大文件限制。 第二,对于需要写入数据的操作,比如DELETE、UPDATE以及INSERT操作,索引会降低它们的速度。这是因为MySQL不仅要把改动数据写入数据文件,而且它还要把这些改动写入索引文件。 【结束语】在大型数据库中,索引是提高速度的一个关键因素。不管表的结构是多么简单,一次500000行的表扫描操作无论如何不会快。如果你的网站上也有这种大规模的表,那么你确实应该花些时间去分析可以采用哪些索引,并考虑是否可以改写查询以优化应用。要了解更多信息,请参见MySQL manual。另外注意,本文假定你所使用的MySQL是3.23版,部分查询不能在3.22版MySQL上执行。 MySQL群集双机模拟 硬件配置 普通PC server * 2 (最小集群环境需要4台服务器) 模拟环境 red hat linux9 for x86 (or red hat AS 2以上版本),glibc-2.2, static, gcc MySQL版本4.1.12 binares mysql-max binary版本目前只支持linux、max os x和solaris 本方案不涉及从源代码编译安装 主机 IP地址 用途 ndb1_mgmd_sqld 1192.168.1.100 Ndb node1+mgmd node1+sqld node1 ndb2_sqld2 192.168.1.200 Ndb node2+sqld node2 Mgmd:management server sqld:mysql server ndb:storaged node (share-nothing,base in memory) 安装 从http://dev.mysql.com/downloads/mysql/4.1.html下载mysql-max-4.1.12-pc-linux-gnu-i686.tar.gz到/var/tmp Storage and SQL Node Installation 在两台主机上执行如下过程 shell>groupadd mysql shell>useradd -g mysql mysql shell>tar zxfv mysql-max-4.1.12-pc-linux-gnu-i686.tar.gz shell>cp -vr mysql-max-4.1.12-pc-linux-gnu-i686 /usr/local/mysql-max-4.1.12-pc-linux-gnu-i686 shell>cd /usr/local shell>ln -s mysql-max-4.1.12-pc-linux-gnu-i686 mysql shell>cd mysql;scripts/mysql_install_db –user=mysql shell>chown -R root .;chown -R mysql data;chgrp -R mysql . shell>cp support-files/mysql.server /etc/rc.d/init.d/ shell>chmod +x /etc/rc.d/init.d/mysql.server shell>chkconfig --add mysql.server shell>chkconfig –level 3 mysql.server off Management Node Installation 在主机ndb1_mgmd_sqld1上执行如下过程 shell>cd /var/tmp shell>tar -zxvf mysql-max-4.1.12a-pc-linux-gnu-i686.tar.gz /usr/local/bin '*/bin/ndb_mgm*' Configuration Configuring the Storage and SQL Nodes 在两台主机上执行如下过程: shell>vi /etc/my.cnf [MYSQLD] # Options for mysqld process: ndbcluster # run NDB engine ndb-connectstring=192.168.1.100 # location of MGM node [MYSQL_CLUSTER] # Options for ndbd process: ndb-connectstring=192.168.1.100 # location of MGM node Configuring the Management Node 在主机ndb1_mgmd_sqld1上执行如下过程 shell>mkdir /var/lib/mysql-cluster shell>cd /var/lib/mysql-cluster shell>vi config.ini [NDBD DEFAULT] # Options affecting ndbd processes on all data nodes: NoOfReplicas=2 # Number of replicas DataMemory=80M # How much memory to allocate for data storage IndexMemory=52M # How much memory to allocate for index storage # For DataMemory and IndexMemory, we have used the # default values. Since the "world" database takes up # only about 500KB, this should be more than enough for # this example Cluster setup. [TCP DEFAULT] [NDB_MGMD] # Management process options: hostname=192.168.1.100 # Hostname or IP address of MGM node datadir=/var/lib/mysql-cluster # Directory for MGM node logfiles [NDBD] # Options for data node "A": # (one [NDBD] section per data node) HostName=192.168.1.100 # Hostname or IP address DataDir=/usr/local/mysql/data # Directory for this data node's datafiles [NDBD] # Options for data node "B": hostname=192.168.1.200 # Hostname or IP address datadir=/usr/local/mysql/data # Directory for this data node's datafiles [MYSQLD] # SQL node options: hostname=192.168.1.100 # Hostname or IP address # Directory for SQL node's datafiles # (additional mysqld connections can be # specified for this node for various # purposes such as running ndb_restore) [MYSQLD] # SQL node options: hostname=192.168.1.200 # Hostname or IP address # Directory for SQL node's datafiles # (additional mysqld connections can be # specified for this node for various # purposes such as running ndb_restore) 第一次启动 在主机ndb1_mgmd_sqld1上执行如下过程 shell> ndb_mgmd -f /var/lib/mysql-cluster/config.ini 在两台主机上执行如下过程 shell>ndbd –initial (note:--initial选项只能在第一次启动的时候使用) shell>/etc/init.d/mysql.server start 测试 在主机ndb1_mgmd_sqld1上执行如下过程 shell> ndb_mgm -- NDB Cluster -- Management Client -- ndb_mgm> show Connected to Management Server at: localhost:1186 Cluster Configuration --------------------- [ndbd(NDB)] 2 node(s) id=2 @192.168.0.100 (Version: 4.1.12, Nodegroup: 0, Master) id=3 @192.168.0.200 (Version: 4.1.12, Nodegroup: 0) [ndb_mgmd(MGM)] 1 node(s) id=1 @192.168.0.100 (Version: 4.1.12) [mysqld(SQL)] 1 node(s) id=4 (Version: 4.1.12) 出现如上信息则表示mysql群集安装成功 数据抽样测试 在主机ndb1_mgmd_sqld1上执行如下过程 shell>/usr/local/mysql/bin/mysql -u root test MySQL>DROP TABLE IF EXISTS City; CREATE TABLE City ( ID int(11) NOT NULL auto_increment, Name char(35) NOT NULL default '', CountryCode char(3) NOT NULL default '', District char(20) NOT NULL default '', Population int(11) NOT NULL default '0', PRIMARY KEY (ID) ) ENGINE=NDBCLUSTER; MySQL>INSERT INTO City VALUES (1,'Kabul','AFG','Kabol',1780000); INSERT INTO City VALUES (2,'Qandahar','AFG','Qandahar',237500); INSERT INTO City VALUES (3,'Herat','AFG','Herat',186800); 在主机ndb2_sqld2上执行如下过程 shell>/usr/local/mysql/bin/mysql -u root mysql MySQSL>select * from City; 如果成功显示数据信息,则表示集群已经成功启动 Safe Shutdown and Restart 在主机ndb1_mgmd_sqld1上执行如下过程 shell>ndb_mgm -e shutdown (关闭集群服务器,storage node也会自动被关闭) 在两台主机上执行如下过程 shell>/etc/init.d/mysql.server stop 重新启动集群(顺序不能弄错) 在主机ndb1_mgmd_sqld1上执行如下过程 shell> ndb_mgmd -f /var/lib/mysql-cluster/config.ini 在两台主机上执行如下过程 shell>/usr/local/mysql/bin/ndbd 启动完ndbd进程后启动sqld进程 shell>/etc/init.d/mysql.server start 附: config.ini中各部分解释 [COMPUTER]: 定义群集主机. [NDBD]: 定义群集数据节点. [MYSQLD]: 定义Sql server节点. [MGM|NDB_MGMD]: Defines the management server node in the cluster. [TCP]: Defines TCP/IP connections between nodes in the cluster, with TCP/IP being the default connection protocol. [SHM]: Defines shared-memory connections between nodes. 在MySQL 4.1.9之前,这个功能必须使用--with-ndb-shm option编译进去, 从MySQL 4.1.9-max版本开始, it is enabled by default(默认为打开状态). MySQL查询优化--数据类型与效率 这一部分提供了如何选择数据类型来帮助提高查询运行速度的一些指导: 根据的PROCEDURE ANALYSE()输出信息,你可能发现,可以修改自己的数据表来利用那些效率更高的数据类型。如果你决定改变某个数据列的类型,需要使用ALTER TABLE语句。 MySQL字段类型说明 MySQL支持大量的列类型,它可以被分为3类:数字类型、日期和时间类型以及字符串(字符)类型。本节首先给出可用类型的一个概述,并且总结每个列类型的存储需求,然后提供每个类中的类型性质的更详细的描述。概述有意简化,更详细的说明应该考虑到有关特定列类型的附加信息,例如你能为其指定值的允许格式。
由MySQL支持的列类型列在下面。下列代码字母用于描述中: M 注意,如果你指定一个了为ZEROFILL,MySQL将为该列自动地增加UNSIGNED属性。 TINYINT[(M)] [UNSIGNED] [ZEROFILL] MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] INT[(M)] [UNSIGNED] [ZEROFILL] INTEGER[(M)] [UNSIGNED] [ZEROFILL] BIGINT[(M)] [UNSIGNED] [ZEROFILL] 一个大整数。有符号的范围是-9223372036854775808到9223372036854775807,无符号的范围是0到 18446744073709551615。注意,所有算术运算用有符号的BIGINT或DOUBLE值完成,因此你不应该使用大于 9223372036854775807(63位)的有符号大整数,除了位函数!注意,当两个参数是INTEGER值时,-、+和*将使用BIGINT运算!这意味着如果你乘2个大整数(或来自于返回整数的函数),如果结果大于9223372036854775807,你可以得到意外的结果。一个浮点数字,不能是无符号的,对一个单精度浮点数,其精度可以是<=24,对一个双精度浮点数,是在25 和53之间,这些类型如FLOAT和DOUBLE类型马上在下面描述。FLOAT(X)有对应的FLOAT和DOUBLE相同的范围,但是显示尺寸和小数位数是未定义的。在MySQL3.23中,这是一个真正的浮点值。在更早的MySQL版本中,FLOAT(precision)总是有2位小数。该句法为了ODBC兼容性而提供。 FLOAT[(M,D)] [ZEROFILL] DOUBLE[(M,D)] [ZEROFILL] DOUBLE PRECISION[(M,D)] [ZEROFILL] REAL[(M,D)] [ZEROFILL] DECIMAL[(M[,D])] [ZEROFILL] NUMERIC(M,D) [ZEROFILL] DATE DATETIME TIMESTAMP[(M)] YEAR[(2|4)] CHAR(M) [BINARY] [NATIONAL] VARCHAR(M) [BINARY] TINYBLOB TEXT MEDIUMBLOB ENUM('value1','value2',...) SET('value1','value2',...) MySQL开发中的外键与参照完整性参照完整性(Referential integrity)是数据库设计中一个重要的概念。在系统不同的列表中,当数据库所有参照合法或非合法关联时都会涉及到参照完整性。当参照完整性存在时,任何与不存在记录的关联将变得无效化,由此可防止用户出现各种错误,从而提供更为准确和实用的数据库。 参照完整性通常通过外键(foreign key)的使用而被广泛应用。长久以来,流行工具开源RDBMS MySQL并没有支持外键,原因是这种支持将会降低RDBMS的速度和性能。然而,由于很多用户对参照完整性的优点倍感兴趣,最近MySQL的不同版本都通过新InnoDB列表引擎支持外键。由此,在数据库组成的列表中保持参照完整性将变得非常简单。 为了建立两个MySQL表之间的一个外键关系,必须满足以下三种情况: 两个表必须是InnoDB表类型。 表A mysql> CREATE TABLE species (id TINYINT NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, PRIMARY KEY(id)) ENGINE=INNODB; mysql> INSERT INTO species VALUES (1, 'orangutan'), (2, 'elephant'), (3, 'hippopotamus'), (4, 'yak'); mysql> CREATE TABLE zoo (id INT(4) NOT NULL, name VARCHAR(50) NOT NULL, FK_species TINYINT(4) NOT NULL, INDEX (FK_species), FOREIGN KEY (FK_species) REFERENCES species (id), PRIMARY KEY(id)) ENGINE=INNODB; 注意:对于非InnoDB表, FOREIGN KEY 语句将被忽略。 现在,fieldszoo.species与species.id 之间存在一个外键关系。只有相应的zoo.specie与species.idfield的一个值相匹配,动物表中的入口才可被访问。以下的输出即演示了当你想输入一个Harry Hippopotamus记录,而使用到不合法的species代码: mysql> INSERT INTO zoo VALUES (1, 'Harry', 5); 这里,MySQL核查species表以查看species代码是否存在,如果发现不存在,就拒绝该记录。当你输入正确代码的,可以与以上做比较。 mysql> INSERT INTO zoo VALUES (1, 'Harry', 3); 这里,MySQL核查species表以查看species代码是否存在,当发现存在,允许记录保存在zoo表中。 为了删除一个外键关系,首先使用SHOW CREATE TABLE找出InnoDB的内部标签,如表B所示: 表 B +-------+---------------------------------------------------+ 然后使用带有DROP FOREIGN KEY 语句的ALTER TABLE命令,如以下: mysql> ALTER TABLE zoo DROP FOREIGN KEY zoo_ibfk_1; 为了将一个外键添加到一个现成的表中,使用ADD FOREIGN KEY的 ALTER TABLE语句指定合适的域作为一个外键: mysql> ALTER TABLE zoo ADD FOREIGN KEY (FK_species) REFERENCES species (id); 如以上例子解释的,外键在捉摸数据入口错误上起着重要的作用,由此可建立更为强健更加集成的数据库。另一方面值得提到的是,执行外键核实是内部资料处理的过程,且不同表之间指定复杂的内部关系可以导致数据库的性能下降。所以,在参照完整性与性能考虑之间找到平衡点相当重要,而使用外键就是能够确保性能与稳健之间的最优结合。 April 18 Mysql 的数据库复制功能Mysql 数据库相信大家已经投入了生产使用。很多人都将他和 PHP 集成在 Apache 中,为WebSite 服务。的确,他们在WebSite 中的应用比较多,而且PhpMyAdmin 又是一个PHP+Mysql 的最好应用例子。 那么Mysql 能不能实现两个系统之间通过TCP/IP去复制数据库?能不能实现实时复制呢?也就是说能不能实现同步(Synchronization)的问题。先概括介绍一下Mysql 的Replication Database功能。 复制(Replication)类似于拷贝数据库到另一台服务器上,但它是通过定义Master 和Slave的关系去实时地保证两个数据库的完全同步。这个功能在Mysql的3.23版中开始出现。 下面大家一起来测试一下Mysql的Replication 功能。 作者的平台是: Master:Mysql 3.23.53-log on FreeBSD 4.7 Release IP:192.168.10.100 1、Master 机器设置权限,赋予Slave Relication 权利,并打包要同步的数据库结构。Slave: Mysql 3.23.56-log on FreeBSD 4.8 Stable IP:192.168.10.200 MasterBSD# pwd (赋予192.168.10.200也就是Slave 机器有File权限)/usr/local/mysql/bin MasterBSD#./mysql –u root –p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 to server version: 3.23.53-log Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> GRANT FILE ON *.* TO replication@192.168.10.200 IDENTIFIED BY ‘repplication’; 然后打包要复制的数据库 MasterBSD# cd var
MasterBSD# tar czvf repdatabase.tar.gz repdatabase 这样,我们的到一个repdatabase数据库的打包文件repdatabase.tar.gz 2设置主服务器Master的my.cnf,启动Mysql服务MasterBSD# vi /etc/my.cnf 在[mysqld]添加或修改以下的[mysqld] 针对repdatabase 库做replication 功能log-bin server-id=1 sql-bin-update-same binlog-do-db= repdatabase 然后把Master主服务器的Mysql重启。 MasterBSD# /usr/local/mysql/bin/mysqladmin –u root –p shutdown 3、建立Slave数据库MasterBSD# /usr/local/mysql/bin/safe_mysqld --user=mysql & 刚才我们在Master中打包了repdatabase.tar.gz,它的作用就是要在Slave恢复成一样的数据库。先把Master 的repdatabase.tar.gz文件传到Slave机器中去。然后 SlaveBSD# tar zxvf repdatabase.tar.gz -C /usr/local/mysql/var/ 4、修改Slave服务器的my.cnf SlaveBSD# vi /etc/my.cnf 在[mysqld]添加或修改以下的master-host=192.168.10.100 5、重启动Slave的slave start。master-user=replication master-password=replication master-port=3306 server-id=2 master-connect-retry=60 replicate-do-db=reldatabase [要更新的数据库] log-slave-updates SlaveBSD# /usr/local/mysql/bin/mysqladmin –u root –p shutdown 6、测试SlaveBSD# /usr/local/mysql/bin/safe_mysqld --user=mysql & 先检测两个Mysql数据库中的repdatabase是否正常。 正常情况应该是Master和Slave 中的Mysql 都有相同的repdatabase 数据库,并且里面的数据都一样。 然后我们测试replication 功能是否起用。 在Master中的repdatabas数据库添加一笔数据: MasterBSD# /usr/local/mysql/bin/mysql -uroot -p 在Slave的数据库中应该也会同样有这样一条数据Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 12 to server version: 3.23.53-log Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> use repdatabase; SlaveBSD# /usr/local/mysql/bin/mysql -uroot -p 到此,我们的两个数据库replication 功能实验成功。
Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 17 to server version: 3.23.56-log Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> select * from repdatabase.rep_table; +--------+-----------+------------+ | name | num | selectd | +--------+-----------+------------+ | aaa | 44444 | N | | ddd | 111112222 | N | | insert | 1234 | N | | test | 12345 | N | | test1 | 4321 | Y | 这一行就是Master插入的时候Slave 同步得回来的数据。 +--------+-----------+------------+ 5 rows in set (0.01 sec) mysql> 7、互为replication 在Mysql 的文档资料中也指出了,一台Mysql机器同样可以作为Master也可以作为Slave的,也可以互相replication数据。 8、应用 replication可以用在那方面呢?我的想法是,一台Mysql生产机器在提供繁忙的SQL查询,比如说是股市的查询,那它仅仅是作为查询而已。那么我们就可以通过两台机器,提供查询的机器为Slave,那么数据录入的机器是Master,通过双网卡去进行,请看下图: 这样的好处是显而易见,Slave作为大量SQL查询的服务器,繁忙、任务大!而且对着Internet,破坏可能性也大!因此,引入Mysql的replication我们可以方便、安全地管理数据库! April 12 mysql 5.1的计划任务mysql的网站上多了一个关于5.1新特性Event(事件)的介绍 ,咋一看象是windows的计划任务,细一看,呵呵,正是如此.假如你有这样的需求--在今年年底之前,每天给我查查用户表里新增了哪些美女,说不定就可以用上Events特性了,下面是新建立Event的语法 SQL:
而要开启或关闭这个特性,只要执行下面的sql: SQL:
不管怎么说,mysql的新版本是越来越强大了,但是在实际的项目中,还没有机会用上它们,很难说性能上是不是会打上折扣 January 14 mysql的表只读可能是文件系统只读, 比如,这个表的文件,相对于系统中的mysql用户,只读,所以,无法修改。 chown mysql.mysql tablename.* chmod u+w tablename November 11 linux下mysql用户访问限制问题mysql.cnf里面有mysqld这个section中有没有bind-address这一个条目
或service iptables stop 看到了,bind-address 是127.0.0.1 注释当然也可以,重启mysql daemon October 31 什么是数据库事务什么是数据库事务 数据库事务是指作为单个逻辑工作单元执行的一系列操作。 设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作: · 更新客户所购商品的库存信息 · 保存客户付款信息--可能包括与银行系统的交互 · 生成订单并且保存到数据库中 · 更新用户相关信息,例如购物数量等等 正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态--库存信息没有被更新、用户也没有付款,订单也没有生成。否则,数据库的信息将会一片混乱而不可预测。 数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术。 数据库事务的ACID属性 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性: · 原子性 事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处理操作子集的可能性。 · 一致性 事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。某些维护一致性的责任由应用程序开发人员承担,他们必须确保应用程序已强制所有已知的完整性约束。例如,当开发用于转帐的应用程序时,应避免在转帐过程中任意移动小数点。 · 隔离性 由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。当事务可序列化时将获得最高的隔离级别。在此级别上,从一组可并行执行的事务获得的结果与通过连续运行每个事务所获得的结果相同。由于高度隔离会限制可并行执行的事务数,所以一些应用程序降低隔离级别以换取更大的吞吐量。 · 持久性 事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。 DBMS的责任和我们的任务 企业级的数据库管理系统(DBMS)都有责任提供一种保证事务的物理完整性的机制。就常用的SQL Server2000系统而言,它具备锁定设备隔离事务、记录设备保证事务持久性等机制。因此,我们不必关心数据库事务的物理完整性,而应该关注在什么情况下使用数据库事务、事务对性能的影响,如何使用事务等等。 October 26 ADODB快速手册1、简要说明 2、安装 3、使用 4、函数 可以的值为: (不包括括号里的内容)
5、对象 6、ADOConnection 对象说明 2、连接数据库 3、执行SQL指令 4、Affected_Rows()函数 5、日期格式 7、Select指令的Limit及Top支持 9、事务 10、SetFetchMode 12、GetInsertSQL , GetUpdateSQL $sql = "SELECT * FROM ADOXYZ WHERE id = -1"; # 从资料库中查询出一个空的资料集 $record = array(); # 初始化一个阵列,以便存放记录资料供新增用 # 设定记录中的栏位值 # 传入空的资料集及栏位资料阵列到GetInsertSQL函数中,以执行功能 $insertSQL = $conn->GetInsertSQL($rs, $record); $conn->Execute($insertSQL); # 将记录挿入资料库中 #========================== $sql = "SELECT * FROM ADOXYZ WHERE id = 1"; $rs = $conn->Execute($sql); # 执行这个查询,并取得一个存在的记录来更新 $record = array(); # 初始化一个阵列,以存放要更新的资料 # 设定栏位里的值 # 传入这个只有单一记录的资料集以及含有资料的阵列到 GetUpdateSQL函数里 $conn->Execute($updateSQL); # 更新资料库中的记录 13、PageExecute 分页查询
7、Recordset 对象 2、RecordCount() 或 RowCount() 3、EOF 4、fields 6、MoveFirst 7、FetchNextObject() 8、Insert_ID 9、MetaTypes 10、FetchField 11 UserDate October 14 MySQL乱码终极解决方案从MySQL 4.1开始引入的多语言支持确实很棒,而且一些特性已经超过了其他的数据库系统。不过在测试过程中发现使用适用于MySQL 4.1之前的PHP语句操作MySQL数据库会造成乱码,即使是设置过了表字符集也是如此。 当我们按照原来的方式通过PHP存取MySQL数据库时,就算设置了表的默认字符集为utf8并且通过UTF-8编码发送查询,你会发现存入数据库的仍然是乱码。 October 12 一个Mysql自动备份脚本可以将这个脚本放进crontab,每天凌晨执行一次,自动备份 这个脚本每天最多只执行一次,而且只保留最近五天的备份在服务器上。 [code:1:893e3c81e2] #!/bin/bash #This is a ShellScript For Auto DB Backup #Powered by aspbiz #2004-09 #Setting #设置数据库名,数据库登录名,密码,备份路径,日志路径,数据文件位置,以及备份方式 #默认情况下备份方式是tar,还可以是mysqldump,mysqldotcopy #默认情况下,用root(空)登录mysql数据库,备份至/root/dbxxxxx.tgz DBName=mysql DBUser=root DBPasswd= BackupPath=/root/ LogFile=/root/db.log DBPath=/var/lib/mysql/ #BackupMethod=mysqldump #BackupMethod=mysqlhotcopy #BackupMethod=tar #Setting End NewFile="$BackupPath"db$(date +%y%m%d).tgz DumpFile="$BackupPath"db$(date +%y%m%d) OldFile="$BackupPath"db$(date +%y%m%d --date='5 days ago').tgz echo "-------------------------------------------" >> $LogFile echo $(date +"%y-%m-%d %H:%M:%S") >> $LogFile echo "--------------------------" >> $LogFile #Delete Old File if [ -f $OldFile ] then rm -f $OldFile >> $LogFile 2>&1 echo "[$OldFile]Delete Old File Success!" >> $LogFile else echo "[$OldFile]No Old Backup File!" >> $LogFile fi if [ -f $NewFile ] then echo "[$NewFile]The Backup File is exists,Can't Backup!" >> $LogFile else case $BackupMethod in mysqldump) if [ -z $DBPasswd ] then mysqldump -u $DBUser --opt $DBName > $DumpFile else mysqldump -u $DBUser -p$DBPasswd --opt $DBName > $DumpFile fi tar czvf $NewFile $DumpFile >> $LogFile 2>&1 echo "[$NewFile]Backup Success!" >> $LogFile rm -rf $DumpFile ;; mysqlhotcopy) rm -rf $DumpFile mkdir $DumpFile if [ -z $DBPasswd ] then mysqlhotcopy -u $DBUser $DBName $DumpFile >> $LogFile 2>&1 else mysqlhotcopy -u $DBUser -p $DBPasswd $DBName $DumpFile >>$LogFile 2>&1 fi tar czvf $NewFile $DumpFile >> $LogFile 2>&1 echo "[$NewFile]Backup Success!" >> $LogFile rm -rf $DumpFile ;; *) /etc/init.d/mysqld stop >/dev/null 2>&1 tar czvf $NewFile $DBPath$DBName >> $LogFile 2>&1 /etc/init.d/mysqld start >/dev/null 2>&1 echo "[$NewFile]Backup Success!" >> $LogFile ;; esac fi echo "-------------------------------------------" >> $LogFile [/code:1:893e3c81e2] MYSQL出错代码列表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版本过低,不具有本功能 |
|
|