我们致力于一个MySQL知识的分享网站

  |   本站Feed  

mysql索引简单介绍

2009-06-30 13:43:22  |   才被阅读:21 次  |   要评论?
分类: MySQL解错方案  |   发布: OurMySQL  |   来源:这一技客
标签:

今天在看我同事建的几个表时发现有点不对径,所以自已上网温故一下之方面的知识。 温故而知新,可以为师矣

在数据库表中,使用可以大大提高查询速度。不过只是提高效率的一个因素。如果你的MySQL有大数据的表,就需要花时间研究建立最优秀的或优化查询语句。

    一、分单列和组合索引

    单列:即一个索引只包含单个列,一个表可以有多个单列,但这不是组合
    组合:即一个索包含多个列。

    二、介绍一下的类型

    1.普通
    这是最基本的,它没有任何限制。它有以下几种创建方式:
    (1)创建索引:CREATE INDEX indexName ON tableName(tableColumns(length));如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是 BLOB 和 TEXT 类型,必须指定length,下同。
    (2)修改表结构:ALTER tableName ADD INDEX [indexName] ON (tableColumns(length))
    (3)创建表的时候直接指定:CREATE TABLE tableName ( [...], INDEX [indexName] (tableColumns(length)) ;

    2.唯一
    它与前面的”普通索引”类似,不同的就是:列的值必须唯一,但允许有空值。如果是组合,则列值的组合必须唯一。它有以下几种创建方式:
    (1)创建索引:CREATE UNIQUE INDEX indexName ON tableName(tableColumns(length))
    (2)修改表结构:ALTER tableName ADD UNIQUE [indexName] ON (tableColumns(length))
    (3)创建表的时候直接指定:CREATE TABLE tableName ( [...], UNIQUE [indexName] (tableColumns(length));

    3.主键索引
    它是一种特殊的唯一,不允许有空值。一般是在建表的时候同时创建主键:CREATE TABLE testIndex(i_testID INT NOT NULL AUTO_INCREMENT,vc_Name VARCHAR(16) NOT NULL,PRIMARY KEY(i_testID)); 当然也可以用ALTER命令。
记住:一个表只能有一个主键。

    4.全文索引
    MySQL从3.23.23版开始支持全文和全文检索。这里不作讨论,删除的语法:DROP INDEX index_name ON tableName

    三、单列和组合索引

    为了形象地对比两者,再建一个表:

CREATE TABLE myIndex ( i_testID INT NOT NULL AUTO_INCREMENT, vc_Name VARCHAR(50) NOT NULL, vc_City VARCHAR(50) NOT NULL, i_Age INT NOT NULL, i_SchoolID INT NOT NULL, PRIMARY KEY (i_testID) );

    在这10000条记录里面7上8下地分布了5条vc_Name=”erquan”的记录,只不过city,age,school的组合各不相同。来看这条 T-SQL: SELECT i_testID FROM myIndex WHERE vc_Name=@#erquan@# AND vc_City=@#郑州@# AND i_Age=25;

    首先考虑建单列
    在vc_Name列上建立了。执行T-SQL时,MYSQL很快将目标锁定在了vc_Name=erquan的5条记录上,取出来放到一中间结果集。在这个结果集里,先排除掉vc_City不等于”郑州”的记录,再排除i_Age不等于25的记录,最后筛选出唯一的符合条件的记录。

    虽然在vc_Name上建立了,查询时MYSQL不用扫描整张表,效率有所提高,但离我们的要求还有一定的距离。同样的,在vc_City和i_Age分别建立的单列的效率相似。

    为了进一步榨取MySQL的效率,就要考虑建立组合。就是将vc_Name,vc_City,i_Age建到一个索引里:

 ALTER TABLE myIndex ADD INDEX name_city_age (vc_Name(10),vc_City,i_Age);

–注意了,建表时,vc_Name长度为50,这里为什么用10呢?因为一般情况下名字的长度不会超过10,这样会加速查询速度,还会减少文件的大小,提高INSERT的更新速度。

    执行T-SQL时,MySQL无须扫描任何记录就到找到唯一的记录!!

    肯定有人要问了,如果分别在vc_Name,vc_City,i_Age上建立单列,让该表有3个单列,查询时和上述的组合效率一样吧?嘿嘿,大不一样,远远低于我们的组合索引~~虽然此时有了三个索引,但MySQL只能用到其中的那个它认为似乎是最有效率的单列

    建立这样的组合,其实是相当于分别建立了

vc_Name,vc_City,i_Age
vc_Name,vc_City
vc_Name

    这样的三个组合!为什么没有vc_City,i_Age等这样的组合呢?这是因为mysql组合索引”最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这三列的查询都会用到该组合,下面的几个T-SQL会用到:

SELECT * FROM myIndex WHREE vc_Name=”erquan” AND vc_City=”郑州”
SELECT * FROM myIndex WHREE vc_Name=”erquan”

    而下面几个则不会用到:

SELECT * FROM myIndex WHREE i_Age=20 AND vc_City=”郑州”
SELECT * FROM myIndex WHREE vc_City=”郑州”

四、使用索引

    到此你应该会建立、使用了吧?但什么情况下需要建立呢?一般来说,在WHERE和JOIN中出现的列需要建立,但也不完全如此,因为 MySQL只对 <,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE(后面有说明)才会使用
SELECT t.vc_Name FROM testIndex t LEFT JOIN myIndex m ON t.vc_Name=m.vc_Name WHERE m.i_Age=20 AND m.vc_City=@#郑州@# 时,有对myIndex表的vc_City和i_Age建立的需要,由于testIndex表的vc_Name开出现在了JOIN子句中,也有对它建立的必要。

    刚才提到了,只有某些时候的LIKE才需建立?是的。因为在以通配符 % 和 _ 开头作查询时,MySQL不会使用,如

SELECT * FROM myIndex WHERE vc_Name like@#erquan%@#

    会使用,而

SELECT * FROM myIndex WHEREt vc_Name like@#%erquan@#

    就不会使用了。

    五、的不足之处

    上面说了那么多的好话,它真的有像传说中那么优秀么?当然会有缺点了。

    1.虽然大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下文件

    2.建立会占用磁盘空间的文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合文件的会膨胀很快。

高效的MySQL分页

2009-06-28 23:28:30  |   才被阅读:52 次  |   要评论?
分类: MySQL优化设计  |   发布: OurMySQL  |   来源:超群.com
标签:

PERCONA PERFORMANCE CONFERENCE 2009上,来自雅虎的几位工程师带来了一篇”Efficient Pagination Using MySQL“的报告,有很多亮点,本文是在原文基础上的进一步延伸。

首先看一下分页的基本原理:

mysql> explain SELECT * FROM message ORDER BY id DESC LIMIT 10000, 20\G
***************** 1. row **************
id: 1
select_type: SIMPLE
table: message
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
rows: 10020
Extra:
1 row in set (0.00 sec)

limit 10000,20的意思扫描满足条件的10020行,扔掉前面的10000行,返回最后的20行,问题就在这里,如果是limit 100000,100,需要扫描100100行,在一个高并发的应用里,每次查询需要扫描超过10W行,性能肯定大打折扣。文中还提到limit n性能是没问题的,因为只扫描n行。

文中提到一种”clue”的做法,给翻页提供一些”线索”,比如还是SELECT * FROM message ORDER BY id DESC,按id降序分页,每页20条,当前是第10页,当前页条目id最大的是9527,最小的是9500,如果我们只提供”上一页”、”下一页”这样的跳转(不提供到第N页的跳转),那么在处理”上一页”的时候SQL语句可以是:

SELECT * FROM message WHERE id > 9527 ORDER BY id ASC LIMIT 20;

处理”下一页”的时候SQL语句可以是:

SELECT * FROM message WHERE id < 9500 ORDER BY id DESC LIMIT 20;

不管翻多少页,每次查询只扫描20行。

缺点是只能提供”上一页”、”下一页”的链接形式,但是我们的产品经理非常喜欢”<上一页 1 2 3 4 5 6 7 8 9 下一页>”这样的链接方式,怎么办呢?

如果LIMIT m,n不可避免的话,要优化效率,只有尽可能的让m小一下,我们扩展前面的”clue”做法,还是SELECT * FROM message ORDER BY id DESC,按id降序分页,每页20条,当前是第10页,当前页条目id最大的是9527,最小的是9500,比如要跳到第8页,我看的SQL语句可以这样写:

SELECT * FROM message WHERE id > 9527 ORDER BY id ASC LIMIT 20,20;

跳转到第13页:

SELECT * FROM message WHERE id < 9500 ORDER BY id DESC LIMIT 40,20;

原理还是一样,记录住当前页id的最大值和最小值,计算跳转页面和当前页相对偏移,由于页面相近,这个偏移量不会很大,这样的话m值相对较小,大大减少扫描的行数。其实传统的limit m,n,相对的偏移一直是第一页,这样的话越翻到后面,效率越差,而上面给出的方法就没有这样的问题。

注意SQL语句里面的ASC和DESC,如果是ASC取出来的结果,显示的时候记得倒置一下。

已在60W数据总量的表中测试,效果非常明显。

Xtrabackup:MySQL DBA的必备工具

2009-06-28 00:04:28  |   才被阅读:40 次  |   要评论?
分类: MySQL初级应用  |   发布: OurMySQL  |   来源:老王的技术手册
标签:

Xtrabackuppercona开发的产品,可以看做是InnoDB Hotbackup的免费替代品。

先看看如何安装Xtrabackup,下载最新的版本,最简单的安装方式无疑是使用RPM包,不过如果你想使用源代码方式安装的话,则会发现其安装方式有点古怪,这是因为它采用的在MySQL源代码上打补丁构建的方式。

wget http://www.percona.com/mysql//-0.8.tar.gz
tar zxf -0.8.tar.gz
cd -0.8
./configure
make

进行到这里时,千万别惯性使然接着make install,那样就会接着安装MySQL了,正确方法是接着:

cd innobase//
make
make install

如此一来,就会在你的/usr/bin目录里安装上两个有用的工具:xtrabackup,innobackupex-1.5.1:

xtrabackup可以在不加锁的情况下备份innodb数据表,不过此工具不能操作myisam。
innobackupex-1.5.1是一个脚本封装,能同时处理innodb和myisam,但在处理myisam时需要加一个读锁。

按如上的介绍,由于操作myisam时需要加读锁,这会堵塞线上服务的写操作,而innodb没有这样的限制,所以数据库中innodb表类型所占的比例越大,则越有利。实际应用中一般是直接使用innobackupex-1.5.1方法,它主要有三种操作方式,按手册中的介绍:

Usage:
innobackup [--sleep=MS] [--compress[=LEVEL]] [--include=REGEXP] [--user=NAME]
           [--password=WORD] [--port=PORT] [--socket=SOCKET] [--no-timestamp]
           [--ibbackup=IBBACKUP-BINARY] [--slave-info] [--stream=tar]
           [--defaults-file=MY.CNF]
           [--databases=LIST] [--remote-host=HOSTNAME] BACKUP-ROOT-DIR
innobackup –apply-log [--use-memory=MB] [--uncompress] [--defaults-file=MY.CNF]
           [--ibbackup=IBBACKUP-BINARY] BACKUP-DIR
innobackup –copy-back [--defaults-file=MY.CNF] BACKUP-DIR

第一个命令行是热备份mysql数据库。

The first line above makes a hot backup of a MySQL database.
By default it creates a backup directory (named by the current date
and time) in the given backup root directory. With the –no-timestamp
option it does not create a time-stamped backup directory, but it puts
the backup in the given directory (which must not exist). This
makes a complete backup of all MyISAM and InnoDB tables and
indexes in all databases or in all of the databases specified with the
–databases option. The created backup contains .frm, .MRG, .MYD,
.MYI., .TRG, .TRN, .opt, and InnoDB data and log files. The MY.CNF
options file defines the location of the database. This
connects to the MySQL server using mysql client program, and runs
ibbackup (InnoDB Hot Backup program) as a child process.

带有–apply-log选项的命令是准备在一个备份上启动mysql服务。

The with –apply-log option prepares a backup for starting a MySQL
server on the backup. This expands InnoDB data files as specified
in BACKUP-DIR/backup-my.cnf using BACKUP-DIR/ibbackup_logfile,
and creates new InnoDB log files as specified in BACKUP-DIR/backup-my.cnf.
The BACKUP-DIR should be a path name of a backup directory created by
innobackup. This runs ibbackup as a child process, but it does not
connect to the database server.

带有–copy-back选项的命令从备份目录拷贝数据,,日志到my.cnf文件里规定的初始位置。

The with –copy-back option copies data, index, and log files
from backup directory back to their original locations.
The MY.CNF options file defines the original location of the database.
The BACKUP-DIR is a path name of a backup directory created by innobackup.

Xtrabackup还可以用来moving InnoDB tables between servers,更多的内容可以参考官方文档例子

参考链接:Xtrabackup online backup for InnoDB/XTraDB(pdf)

升级MySQL过程中出现Unknown command错误

2009-06-25 23:27:13  |   才被阅读:30 次  |   要评论?
分类: MySQL解错方案  |   发布: OurMySQL  |   来源:老王的技术手册
标签: , ,

升级法则第一条:最好不要升级。除非必要,否则任何改变现状的升级操作都有可能给你带来不必要的烦恼。

MySQL4升级到5,本来打算直接使用mysql_upgrade之类的工具升级数据文件,不过考虑从4到5变化太大,便决定使用mysqldump导出数据文件:

先在旧的MySQL4上导出数据:

/path/to/mysql4/bin/mysqldump –all-databases > backup.sql

再在新的MySQL5上导入数据:

/path/to/mysql5/bin/mysql < backup.sql

在导入SQL文件的时候遇到了Unknown command错误,网上查询,发现这个问题可能是由下列原因引起:

第一:可能是default-character-set设置错误。
第二:可能是max_allowed_packet设置过小。

不过这些配置我都已经在客户端配置文件$HOME/.my.cnf里设置过了,所以不可能是这些问题,最后发现竟然是因为在导入导出数据时使用了不同版本的工具所致,换成/path/to/mysql4/bin/mysq导入,不再出现Unknown command错误,兼容性做得不好啊,以后遇到类似问题要注意了。

第三:可能是因为导入导出数据时使用的工具版本不一致所致。

所有的原因中,第三点尤其容易被忽视,如果你遇到了类似的问题,不妨对照这三点一一排查。

使用Xtrabackup备份MySQL数据库

2009-06-25 23:24:59  |   才被阅读:48 次  |   要评论?
分类: MySQL初级应用  |   发布: OurMySQL  |   来源:NinGoo.net
标签:

MySQL数据库的备份,一直是个比较头痛的问题。各种工具虽然不少,但一个真正好用易用的,却又非常难找。Mysqldump做为数据的逻辑备份工具还行,但是无法进行在线热备,而没有物理备份工具,在数据量比较大的时候,恢复的时间也会长得无法接受。InnoDB倒是有个商业的InnoDB Hotbackup,可以对InnoDB引擎的表实现在线热备。最近发现了一个工具,percona出品的Xtrabackup,是InnoDB Hotbackup的一个开源替代品,可以在线对InnoDB/XtraDB引擎的表进行物理备份,试用了一下,非常的不错,值得向MySQL DBA们推荐。

下面是一个实际备份的例子,采用了gzip将备份流进行压缩,约20GB的数据库,压缩后大小为340MB,当然,压缩后的大小跟数据库中实际使用的空间是相关的。备份时间约6分44秒。

innobackupex是参考了InnoDB Hotbackup的innoback脚本修改而来的,主要是为了方便的同时备份InnoDB和MyISAM引擎的表,并且加入了一些使用的选项。如–slave-info可以记录备份恢复后,作为slave需要的一些信息,根据这些信息,可以很方便的利用备份来重做slave。

注意,从备份后的tar包解包的时候,需要使用-i参数。最新发布的是0.7版,猛击这里下载

$innobackupex-1.5.1 –user=root –stream=tar /bak/ –slave-info | gzip > /bak/bak_mysql.tar.gz

InnoDB Backup Utility v1.5.1-; Copyright 2003, 2009 Innobase Oy.
All Rights Reserved.

This software is published under
the GNU GENERAL PUBLIC LICENSE Version 2, June 1991.

IMPORTANT: Please check that the backup run completes successfully.
At the end of a successful backup run innobackup
prints “innobackup completed OK!”.

innobackupex: Using mysql Ver 14.12 Distrib 5.0.67, for redhat-linux-gnu (x86_64)
using EditLine wrapper
innobackupex: Using mysql server version 5.0.67-log

innobackupex: Created backup directory /bak
090625 15:23:00 innobackupex: Starting mysql with options: –unbuffered –user=root
090625 15:23:00 innobackupex: Connected to database with mysql child process (pid=3431)
090625 15:23:04 innobackupex: Connection to database server closed

090625 15:23:04 innobackupex: Starting ibbackup with :
–backup –suspend-at-end –log-stream –target-dir=./
innobackupex: Waiting for ibbackup (pid=3565) to suspend
innobackupex: Suspend file ‘/opt/mysqldata/xtrabackup_suspended’

: suspend-at-end is enabled.
: uses posix_fadvise().
: cd to /opt/mysqldata
: Target instance is assumed as followings.
: innodb_data_home_dir = /opt/mysqldata
: innodb_data_file_path = ibdata1:10G;ibdata2:10G
: innodb_log_group_home_dir = ./
: innodb_log_files_in_group = 4
: innodb_log_file_size = 104857600
: use O_DIRECT
: Stream mode.
>> log scanned up to (0 3053406941)

090625 15:23:06 innobackupex: Continuing after ibbackup has suspended

innobackupex: Starting to backup InnoDB tables and indexes
innobackupex: from original InnoDB data directory ‘/opt/mysqldata’
innobackupex: Backing up as tar stream ‘ibdata1′
>> log scanned up to (0 3053416714)
…这里省略若干行
>> log scanned up to (0 3054123851)
tar: ibdata1: file changed as we read it
innobackupex: Backing up as tar stream ‘ibdata2′
>> log scanned up to (0 3054142116)
…这里省略若干行
>> log scanned up to (0 3054618483)
innobackupex: Backing up file ‘/opt/mysqldata/test/sp.ibd’
innobackupex: Backing up file ‘/opt/mysqldata/test/tmp_dy.ibd’
innobackupex: Backing up files ‘/opt/mysqldata/testdb/*.ibd’ (206 files)
>> log scanned up to (0 3054638401)
>> log scanned up to (0 3054668860)
tar: testdb/group_group_thread_0027.ibd: file changed as we read it
>> log scanned up to (0 3054695015)
>> log scanned up to (0 3054928216)
tar: testdb/group_thread_reply_0007.ibd: file changed as we read it
>> log scanned up to (0 3054952588)
>> log scanned up to (0 3055005439)
tar: testdb/group_user_0001.ibd: file changed as we read it
>> log scanned up to (0 3055028610)
>> log scanned up to (0 3055044650)
tar: testdb/group_user_0006.ibd: file changed as we read it
>> log scanned up to (0 3055060461)
innobackupex: Backing up file ‘/opt/mysqldata/testdb/comments.ibd’
innobackupex: Backing up file ‘/opt/mysqldata/testdb/testdb.ibd’
innobackupex: Backing up file ‘/opt/mysqldata/testdb/testdb_content.ibd’
innobackupex: Backing up file ‘/opt/mysqldata/testdb/testdb_ids.ibd’
090625 15:29:17 innobackupex: Starting mysql with options: –unbuffered –user=root
090625 15:29:17 innobackupex: Connected to database with mysql child process (pid=5458)
>> log scanned up to (0 3055072495)
090625 15:29:21 innobackupex: Starting to lock all tables…
>> log scanned up to (0 3055087148)
>> log scanned up to (0 3055119993)
090625 15:29:39 innobackupex: All tables locked and flushed to disk

090625 15:29:39 innobackupex: Starting to backup .frm, .MRG, .MYD, .MYI,
innobackupex: .TRG, .TRN, and .opt files in
innobackupex: subdirectories of ‘/opt/mysqldata’
innobackupex: Backing up file ‘/opt/mysqldata/test/sp.frm’
innobackupex: Backing up file ‘/opt/mysqldata/test/tmp_dy.frm’
innobackupex: Backing up files ‘/opt/mysqldata/testdb/*.{frm,MYD,MYI,MRG,TRG,TRN,opt}’ (207 files)
innobackupex: Backing up file ‘/opt/mysqldata/testdb/comments.frm’
innobackupex: Backing up file ‘/opt/mysqldata/testdb/testdb.frm’
innobackupex: Backing up file ‘/opt/mysqldata/testdb/testdb_content.frm’
innobackupex: Backing up file ‘/opt/mysqldata/testdb/testdb_ids.frm’
innobackupex: Backing up file ‘/opt/mysqldata/testdb/db.opt’
innobackupex: Backing up files ‘/opt/mysqldata/mysql/*.{frm,MYD,MYI,MRG,TRG,TRN,opt}’ (52 files)
090625 15:29:40 innobackupex: Finished backing up .frm, .MRG, .MYD, .MYI, .TRG, .TRN, and .opt files

innobackupex: Resuming ibbackup

: The latest check point (for incremental): ‘0:3054881736′
>> log scanned up to (0 3055120013)
: Transaction log of lsn (0 3053102766) to (0 3055120013) was copied.
090625 15:29:44 innobackupex: All tables unlocked
090625 15:29:44 innobackupex: Connection to database server closed

innobackupex: Backup created in directory ‘/bak/’
innobackupex: MySQL binlog position: filename ”, position
innobackupex: MySQL slave binlog position: master host ‘127.0.0.1′,
filename ‘mysql-bin.000006′, position 227207755
090625 15:29:44 innobackupex: innobackup completed OK!
innobackupex: You must use -i (–ignore-zeros) option for extraction of the tar stream.