我现在有这么一个表:
table A
filed:
 id
 position
 type其中position与type 建了一个复合索引, id 是主键有两种情况
1.用一种几乎随机的顺序在表A中插入1000W条数据
2.插入1000W条 经过order by position 排序的数据现在执行 
select * from A where position > & and position <& and type = &;为什么两句的执行时间会差上几乎几十倍?

解决方案 »

  1.   

    建一个 position 索引试试
      

  2.   

    explain  结果一模一样的都用到了复合索引extra 都为 using where
      

  3.   

    应该只是在插入时速度有差别,插入数据时,MYSQL会更新索引,
    贴结果出来看看吧
      

  4.   

    把你的大致的操作过程贴出来。你确定没涉及到什么cache?例如query cache。
      

  5.   

    如果都一样,只能用磁盘的存贮来解释了。你顺序插入的时候,每条记录在磁盘基本上是物理顺序放在一个一个簇中,这样一个磁盘簇中,会放着连续的几个记录,当然系统读取的时候只需访问这个簇一次。 如果随机插入,则分分布在不同的物理簇,这样虽然从INDEX中可以立即得到这条记录的物理位置,但读这些相邻记录时却要从不同的物理簇中取得。磁盘的操作时间会有显著差异。连续,仅读一次磁盘即可。 隋机则需读多次磁盘
      

  6.   

    这个说起来比较麻烦,简单的说,关键在I/O的开销上了。
    稍微详细一些,就是:
    X86的机器,CPU处理数据时,现在仍然是用的块操作,也就是每次都要读取一定的量的信息(类似于硬盘在存储数据时用的是簇的概念一样,当然,处理机制完全不一样)。你的数据量太大,即使有索引,在命中之后,如果没有排序,可能这些信息散布在所有块里面,然后每次都把相应的块都提出来,也就是说,他要把这几十万块的数据都读取出来,然后抽取有用数据。
    如果有排序,则只提取那些数据所在的那几千个块里面就可以了。
    每个块,都要有寻址的过程,所以会比较慢。不过,如果是无序的,在MySQL上,建议数据量不要超过900万。
    不知道楼主明白没有。当然了,知道这些东西,当数据量比较大时,对如何建数据表十分重要,数据量比较小时,可以不用考虑I/O的问题。
      

  7.   

    http://dev.mysql.com/doc/refman/5.1/zh/language-structure.html#legal-names9.2. 数据库、表、索引、列和别名9.2.1. 识别符限制条件
    9.2.2. 识别符大小写敏感性数据库、表、索引、列和别名是识别符。该节描述了在MySQL中识别符的允许的语法。下面的表描述了每类识别符的最大长度和允许的字符。识别符
    最大长度(字节)
    允许的字符数据库
    64
    目录名允许的任何字符,不包括‘/’、‘\’或者‘。’表
    64
    文件名允许的任何字符,不包括‘/’、‘\’或者‘。’列
    64
    所有字符索引
    64
    所有字符别名
    255
    所有字符除了表内注明的限制,识别符不可以包含ASCII 0或值为255的字节。数据库、表和列名不应以空格结尾。在识别符中可以使用引号识别符,尽管应尽可能避免这样使用。识别符用Unicode(UTF8)保存。在.frm文件中保存的表定义的识别符和在mysql数据库中的授权表保存的识别符也用Unicode(UTF8)保存。在MySQL 5.1中授权表(和其它表)的字符串列的大小等于字符个数;这说明(不象以前版本的MySQL)你可以在这些列保存的值中使用多字节字符而不需要降低字符个数。识别符可以引起来也可以不引起来。如果识别符是一个保留字或包含特殊字符,无论何时使用,必须将它引起来。关于保留字的列表参见9.6节,“MySQL中保留字的处理”。特殊字符指那些当前字符集、‘_’和‘$’之外的文字数字字符集。识别符的引用符是反勾号(‘`’):mysql> SELECT * FROM `select` WHERE `select`.id > 100;如果SQL服务器模式包括ANSI_QUOTES模式选项,还可以用双引号将识别符引起来:mysql> CREATE TABLE "test" (col INT);ERROR 1064: You have an error in your SQL syntax. (...)mysql> SET sql_mode='ANSI_QUOTES';mysql> CREATE TABLE "test" (col INT);Query OK, 0 rows affected (0.00 sec)参见5.3.2节,“SQL服务器模式”。如果你引用识别符,可以在识别符内包括识别符引用符。如果识别符内包括的字符与引用识别符的字符相同,则需要用双字符。下面的语句创建一个名为a`b包含列c"d的表:mysql> CREATE TABLE `a``b` (`c"d` INT);建议不要使用XeX模式的名,例如1e或2e2,因为类似1e+1的表达式比较模糊。根据上下文,它可以解释为表达式1e + 1或数字1e+1。使用MD5产生表名时应仔细,因为它可能产生不合法的表名,如上所述。
    9.2.1. 识别符限制条件MySQL允许使用由单个识别符或多个识别符组成的名字。多部分名各组件之间应以句点(‘.’)间隔开。多部分名的开头部分作为限定词,后面的识别符被解释。在MySQL中可以引用下面形式的列:列参考
    含义col_name
    列col_name,查询中使用的表包含有此名字的列。tbl_name.col_name
    默认数据库中的表tbl_name的列col_name。db_name.tbl_name.col_name
    数据库db_name中的表tbl_name的列col_name。 如果多部分名的组件需要引用,应分别将它们引起来而不要将整个名引起来。例如,`my-tables`.`my-column` 有效,而`my-tables.my-column`无效。不需要在语句中为列指定tbl_name或db_name.tbl_name前缀,除非列会很模糊。假定表t1和t2各包含一个列c,你使用SELECT语句在t1和t2中搜索c。在这种情况下,c很模糊,因为它在语句中使用的表内不唯一。你必须用表名t1.c或t2.c限定它,表示指哪个表。同样,要想用同一语句搜索数据库db1中的表t和数据库db2中的表t,你必须将那些表中的列指为db1.t.col_name和db2.t.col_name。限定名中句点后面的字必须为一个识别符,因此不需要将它引起来,即使是一个保留字。语法.tbl_name表示当前数据库中的tbl_name。该语法与ODBC兼容,因为某些ODBC程序在表名前面加前缀‘.’字符。
    9.2.2. 识别符大小写敏感性在MySQL中,数据库对应数据目录中的目录。数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎)。因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感性。这说明在大多数Unix中数据库名和表名对大小写敏感,而在Windows中对大小写不敏感。一个显著的例外情况是Mac OS X,它基于Unix但使用默认文件系统类型(HFS+),对大小写不敏感。然而,Mac OS X也支持UFS卷,该卷对大小写敏感,就像Unix一样。参见1.8.4节,“MySQL对标准SQL的扩展”。注释:尽管在某些平台中数据库名和表名对大小写不敏感,不应在同一查询中使用不同的大小写来引用给定的数据库或表。下面的查询不会工作,因为它同时引用了表my_tables和as MY_tables:mysql> SELECT * FROM my_table WHERE MY_TABLE.col=1;列、索引、存储子程序和触发器名在任何平台上对大小写不敏感,列的别名也不敏感。默认情况,表别名在Unix中对大小写敏感,但在Windows或Mac OS X中对大小写不敏感。下面的查询在Unix中不会工作,因为它同时引用了别名a和A:mysql> SELECT col_name FROM tbl_name AS a    -> WHERE a.col_name = 1 OR A.col_name = 2;然而,该查询在Windows中是可以的。要想避免出现差别,最好采用一致的转换,例如总是用小写创建并引用数据库名和表名。在大多数移植和使用中建议使用该转换。在MySQL中如何在硬盘上保存和使用表名和数据库名由lower_case_tables_name系统变量确定,可以在启动mysqld时设置。lower_case_tables_name可以采用下面的任一值:值
    含义0
    使用CREATE TABLE或CREATE DATABASE语句指定的大写和小写在硬盘上保存表名和数据库名。名称比较对大小写敏感。在Unix系统中的默认设置即如此。请注意如果在大小写不敏感的文件系统上用--lower-case-table-names=0强制设为0,并且使用不同的大小写访问MyISAM表名,会导致索引破坏。1
    表名在硬盘上以小写保存,名称比较对大小写敏感。MySQL将所有表名转换为小写以便存储和查找。该行为也适合数据库名和表的别名。该值为Windows和Mac OS X系统中的默认值。2
    表名和数据库名在硬盘上使用CREATE TABLE或CREATE DATABASE语句指定的大小写进行保存,但MySQL将它们转换为小写以便查找。名称比较对大小写敏感。注释:只在对大小写不敏感的文件系统上适用! InnoDB表名以小写保存,例如lower_case_tables_name=1。在Windows和Mac OS X中,lower_case_tables_name的 默认值是1。如果只在一个平台上使用MySQL,通常不需要更改lower_case_tables_name变量。然而,如果你想要在对大小写敏感不同的文件系统的平台之间转移表,会遇到困难。例如,在Unix中,my_tables和MY_tables是两个不同的表,但在Windows中,这两个表名相同。要想避免由于数据库或表名的大小写造成的数据转移问题,可使用两个选项:·         在任何系统中可以使用lower_case_tables_name=1。使用该选项的不利之处是当使用SHOW TABLES或SHOW DATABASES时,看不出名字原来是用大写还是小写。·         在Unix中使用lower_case_tables_name=0,在Windows中使用lower_case_tables_name=2。这样了可以保留数据库名和表名的大小写。不利之处是必须确保在Windows中查询总是用正确大小写引用数据库名和表名。如果将查询转移到Unix中,由于在Unix中大小写很重要,如果大小写不正确,它们不工作。例外:如果你正使用InnoDB表,在任何平台上均应将lower_case_tables_name设置为1,以强制将名转换为小写。请注意在Unix中将lower_case_tables_name设置为1之前,重启mysqld之前,必须先将旧的数据库名和表名转换为小写。