7.4优化数据库结构 7.4.1设计选择 MySQL将记录数据和索引数据分别存放在不同的文件里。其他很多(几乎所有)数据库都将这记录和索引数据存在同一个文件中。我们相信MySQL的选择对于现在更大范围的系统更合适。 另一个存储记录数据的方法是将每个字段的信息保
MySQL将记录数据和索引数据分别存放在不同的文件里。其他很多(几乎所有)数据库都将这记录和索引数据存在同一个文件中。我们相信MySQL的选择对于现在更大范围的系统更合适。
另一个存储记录数据的方法是将每个字段的信息保存在独立的区域中(例如 SDBM 和Focus)。这当每个查询都要访问不只一个字段的时候会打击性能。由于当访问越多的字段后,性能下降的越厉害,因此我们认为这种模式不适合正常目的的数据库。
更多的情况是把索引和数据保存在一起(例如 Oracle/Sysbase等)。这样的话,就能在索引的叶子页面找到记录的信息。这种布局的有利之处在于,很多时候由于索引被缓存的比较好,因此就能节省磁盘读取,不过也有如下缺点:
优化的最基本原则之一就是尽可能把数据表设计的占用更少磁盘空间。这能得到巨大的性能改善,因为磁盘读取比较快,并且越小的表在处理查询内容时只需更少的主内存。在小点的字段上做索引也只需更少的资源负载。
MySQL支持很多种不同的表类型以及记录格式。可以决定每个表要采用那种存储引擎/索引方式。根据不同的应用程序选择适当的表格式能大大提高性能。详情请看“15MySQL Storage Engines and Table Types”。
用以下方法可以提高表性能同时节省存储空间:
MEDIUMINT
通常比更合适 INT
。NOT NULL
。这会运行的更快,而且每个字段都会节省1个bit。如果在应用程序中确实需要用到 NULL
,那么就明确的指定它。不过要避免所有的字段默认值是 NULL
。MyISAM
表中,如果没有用到任何变长字段(VARCHAR
, TEXT
, 或 BLOB
字段)的话,那么就采用固定大小的记录格式。这样速度更快,不过可能会浪费点空间。详情请看“15.1.3 MyISAM
Table Storage Formats”。所有的MySQL字段类型都能被索引。在相关字段上做索引对提高 SELECT
语句的性能最有效。
每个表的最大索引长度以及最多索引数量是由各自的存储引擎定义好了的。详情请看“15 MySQL Storage Engines and Table Types”。所有的存储引擎对每个表都至少可以支持16个索引,索引长度最小是 256 字节。大部分存储引擎的限制更高。
索引格式中使用 <var>col_name</var>(<var>length</var>)
语法,就能只对 CHAR
或 VARCHAR
字段最前面的 length 个字符做索引。象类似这样只对字段的前缀部分做索引能让索引文件更小。
MyISAM
和 InnoDB
(从MySQL 4.0.14开始)存储引擎还支持在 BLOB
和 TEXT
字段上做索引,但是必须指定索引的前缀长度,例如:
CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));
前缀的长度可以多达255字节(从MySQL 4.1.2开始,MyISAM
和 InnoDB
表支持1000字节)。注意,前缀长度限制是以字节数衡量的,然而 CREATE TABLE
语句中的前缀长度理解成为字符个数。因此在指定字段索引前缀长度时要考虑到使用多字节字符集字段的情况了。
从MySQL 3.23.23开始,就可以创建 FULLTEXT
索引了,它们使用全文搜索。只有 MyISAM
表支持对 CHAR
,VARCHAR
和 TEXT
字段做 FULLTEXT
索引。只对整个字段检索有效,不支持部分(前缀)检索。详情请看“13.6 Full-Text Search Functions”。
从MySQL 4.1.0开始,还可以空间类型字段上做索引。目前,只有 MyISAM
存储引擎支持空间类型。空间索引使用R树索引。
MEMORY
(HEAP
) 存储引擎支持哈希索引,从MySQL 4.1.0开始,它也支持B树索引。
MySQL可以在多个字段上创建索引,可以由多达15个字段组成。对特定的字段类型,还可以使用前缀索引(详情请看"7.4.3 Column Indexes”)。
多字段索引可以认为是由索引字段的值连接在一起而成,且经过排序之后的数组。
MySQL以如下方法使用多字段索引:在 WHERE
子句中指定了已知数量的索引的第一个字段,查询就很快了,甚至无需指定其他字段的值。
假定一个表结构如下:
CREATE TABLE test (<br> id INT NOT NULL,<br> last_name CHAR(30) NOT NULL,<br> first_name CHAR(30) NOT NULL,<br> PRIMARY KEY (id),<br> INDEX name (last_name,first_name));<br>
索引 name
覆盖了 last_name
和 first_name
字段。这个索引在字段 last_name
上或 last_name
和 first_name
一起的指定范围内查询时能起到作用。因此这个索引在以下几个查询中都会被用到:
SELECT * FROM test WHERE last_name='Widenius';<br><br>SELECT * FROM test<br> WHERE last_name='Widenius' AND first_name='Michael';<br><br>SELECT * FROM test<br> WHERE last_name='Widenius'<br> AND (first_name='Michael' OR first_name='Monty');<br><br>SELECT * FROM test<br> WHERE last_name='Widenius'<br> AND first_name >='M' AND first_name <br>
不过,索引 name
在以下几个查询中不会被用到:
SELECT * FROM test WHERE first_name='Michael';<br><br>SELECT * FROM test<br> WHERE last_name='Widenius' OR first_name='Michael';<br>
关于MySQL如何使用索引来改善查询性能的方式在下个章节中具体讨论。
‹ MySQL 优化(五)向上MySQL 优化(七) ›