﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>P.Linux Laboratory &#187; Index</title>
	<atom:link href="http://www.penglixun.com/tag/index/feed" rel="self" type="application/rss+xml" />
	<link>http://www.penglixun.com</link>
	<description>MySQL DBA &#38; Linux SA</description>
	<lastBuildDate>Sun, 22 Jan 2012 16:34:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>MySQL中创建及优化索引组织结构的思路</title>
		<link>http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html</link>
		<comments>http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html#comments</comments>
		<pubDate>Thu, 02 Jun 2011 08:22:26 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[Index]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Optimize]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1220</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html 原文链接：http://w... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html </p>
<p></span>原文链接：<a href="http://www.mysqlops.com/2011/05/23/mysql%E4%B8%AD%E5%88%9B%E5%BB%BA%E5%8F%8A%E4%BC%98%E5%8C%96%E7%B4%A2%E5%BC%95%E7%BB%84%E7%BB%87%E7%BB%93%E6%9E%84%E7%9A%84%E6%80%9D%E8%B7%AF.html">http://www.mysqlops.com/2011/05/23/mysql%E4%B8%AD%E5%88%9B%E5%BB%BA%E5%8F%8A%E4%BC%98%E5%8C%96%E7%B4%A2%E5%BC%95%E7%BB%84%E7%BB%87%E7%BB%93%E6%9E%84%E7%9A%84%E6%80%9D%E8%B7%AF.html</a></p>
<p>【导读】<br />
通过一个实际生产环境中的数据存取需求，分析如何设计此存储结构，如何操纵存储的数据，以及如何使操作的成本或代价更低，系统开销最小。同时，让更多初学者明白数据存储的表上索引是如何一个思路组织起来的，希望起到一个参考模板的价值作用。</p>
<p><strong>测试用例描述</strong><br />
测试用例为B2C领域，一张用于存储用户选购物品而生成的产品订单信息表，不过去掉一些其他字段，以便用于测试，其表中的数据项也不特别描述，字段意思见表</p>

<div class="wp_codebox"><table><tr id="p12203"><td class="code" id="p1220code3"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">USE</span> <span style="color: #ff0000;">`test`</span>;
<span style="color: #993333; font-weight: bold;">DROP</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> <span style="color: #ff0000;">`test`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`goods_order`</span>;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`goods_order`</span><span style="color: #66cc66;">&#40;</span>
<span style="color: #ff0000;">`order_id`</span>        INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>      <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>             COMMENT ‘订单单号’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`goods_id`</span>        INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>      <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘商品款号’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`order_type`</span>      TINYINT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>  <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘订单类型’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`order_status`</span>    TINYINT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>  <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘订单状态’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`color_id`</span>        SMALLINT  <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘颜色id’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`size_id`</span>         SMALLINT  <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘尺寸id’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`goods_number`</span>    MEDIUMINT  <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘数量’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`depot_id`</span>        INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>  <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘仓库id’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`packet_id`</span>       INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>  <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘储位code’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`gmt_create`</span>      TIMESTAMP     <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’0000<span style="color: #66cc66;">-</span>00<span style="color: #66cc66;">-</span>00 00:00:00′ COMMENT ‘添加时间’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`gmt_modify`</span>      TIMESTAMP     <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’0000<span style="color: #66cc66;">-</span>00<span style="color: #66cc66;">-</span>00 00:00:00′ COMMENT ‘更新时间’<span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">&#40;</span>order_id<span style="color: #66cc66;">,</span><span style="color: #ff0000;">`goods_id`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>ENGINE<span style="color: #66cc66;">=</span>InnoDB <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span><span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span> CHARACTER <span style="color: #993333; font-weight: bold;">SET</span> ‘utf8′ COLLATE ‘utf8_general_ci’;</pre></td></tr></table></div>

<p>其中，主键信息：PRIMARY KEY(order_id,`goods_id`)，为何主键索引索引字段的顺序为：order_id,`goods_id`，而不是： `goods_id`, order_id呢？原因很简单，goods_id在订单信息表中的重复率会比order_id高，也即order_id的筛选率更高，可以减少扫描索引记录个数，从而达到更高的效率，同时，下面即将会列出的<acronym title="Structured Query Language">SQL</acronym>也告诉我们，有部分<acronym title="Structured Query Language">SQL</acronym>语句的WHERE字句中只出现order_id字段，为此更加坚定我们必须把字段：order_id作为联合主键索引的头部，`goods_id`为联合主键索引的尾部。</p>
<p>数据存储表设计的小结：<br />
设计用于存储数据的表结构，首先要知道有哪些数据项，也即行内常说的数据流，以及各个数据项的属性，比如存储的数据类型、值域范围及长度、数据完整性等要求，从而确定数据项的属性定义。存储的数据项信息确定之后，至少进行如下三步分析：<br />
l  首先，确定哪些数据项或组合，可以作为记录的唯一性标志；<br />
l  其次，要确定对数据记录有哪些操作，每个操作的频率如何，对网站等类型应用，还需要区分前台操作和后台操作，也即分外部用户的操作，还是内部用户的操作；<br />
l  最后，对作为数据记录操作的条件部分的数据项，分析其数据项的筛选率如何，也即数据项不同值占总数据记录数的比例关心，比例越接近1则是筛选率越好，以及各个值得分布率；<br />
综上所述，再让数据修改性操作优先级别高于只读性操作，就可以创建一个满足要求且性能较好的索引组织结构。<br />
数据的存取设计,就涉及一块非常重要的知识: 关系数据库的基础知识和关系数据理论的范式。对于范式的知识点，特别解释下，建议学到BCNF范式为止，1NF、2NF、3NF和BCNF之间的差别，各自规避的问题、存在的缺陷都要一清二楚，但是在真实的工作环境中，不要任何存取设计都想向范式靠，用一句佛语准确点表达：空即是色，色即是空。</p>
<p><strong>用于生成测试数据的存储过程代码</strong><br />
创建索引，就离不开表存储的真实数据，为此编写一个存储过程近可能模拟真实生产环境中的数据，同时也方便大家使用此存储过程，在自己的测试环境中，真实感受验证，<br />
存储过程代码：</p>

<div class="wp_codebox"><table><tr id="p12204"><td class="code" id="p1220code4"><pre class="sql" style="font-family:monospace;">DELIMITER $$
<span style="color: #993333; font-weight: bold;">DROP</span> PROCEDURE <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> <span style="color: #ff0000;">`usp_make_data`</span> $$
<span style="color: #993333; font-weight: bold;">CREATE</span> PROCEDURE <span style="color: #ff0000;">`usp_make_data`</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
BEGIN
DECLARE iv_goods_id INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #cc66cc;">0</span>;
DECLARE iv_depot_id INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #cc66cc;">0</span>;
DECLARE iv_packet_id INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #cc66cc;">0</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">SET</span> iv_goods_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">5000</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_depot_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">10</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_packet_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">20</span>;
&nbsp;
WHILE iv_goods_id&amp;gt;<span style="color: #cc66cc;">0</span>
DO
START  TRANSACTION;
WHILE iv_depot_id&amp;gt;<span style="color: #cc66cc;">0</span>
DO
WHILE iv_packet_id&amp;gt;<span style="color: #cc66cc;">0</span>
DO
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> goods_order<span style="color: #66cc66;">&#40;</span>order_id<span style="color: #66cc66;">,</span>goods_id<span style="color: #66cc66;">,</span>order_type<span style="color: #66cc66;">,</span>order_status<span style="color: #66cc66;">,</span>color_id<span style="color: #66cc66;">,</span>size_id<span style="color: #66cc66;">,</span>goods_number<span style="color: #66cc66;">,</span>depot_id<span style="color: #66cc66;">,</span>packet_id<span style="color: #66cc66;">,</span>gmt_create<span style="color: #66cc66;">,</span>gmt_modify<span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">VALUES</span><span style="color: #66cc66;">&#40;</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>iv_goods_id<span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>%2<span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
iv_depot_id<span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">*</span>iv_packet_id<span style="color: #66cc66;">,</span>DATE_ADD<span style="color: #66cc66;">&#40;</span>NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>INTERVAL <span style="color: #66cc66;">-</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span> DAY<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>DATE_ADD<span style="color: #66cc66;">&#40;</span>NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>INTERVAL <span style="color: #66cc66;">-</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span> DAY<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_packet_id<span style="color: #66cc66;">=</span>iv_packet_id<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span>;
END WHILE;
<span style="color: #993333; font-weight: bold;">SET</span> iv_packet_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">20</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_depot_id<span style="color: #66cc66;">=</span>iv_depot_id<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span>;
END WHILE ;
&nbsp;
COMMIT;
<span style="color: #993333; font-weight: bold;">SET</span> iv_depot_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">10</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_goods_id<span style="color: #66cc66;">=</span>iv_goods_id<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span>;
END WHILE ;
END $$
DELIMITER ;</pre></td></tr></table></div>

<p><strong>业务逻辑描述</strong><br />
l  非注册用户，或网站的注册用户不登陆，都能可选购买物品，生成订单号对应的用户UID为系统默认的；<br />
l  订单与用户UID关联、描述等信息，存储其它的表中，通过订单号的模式关联；<br />
l  用户的订单信息，在未付款之前都可以再修改，付款之后则无法修改；<br />
l  已经付费的订单信息，自动发送到物流部门，进行后续工序的操作。处理完毕之后，会更新订单中涉及物品的存储位置信息；<br />
l  定期读取部分数据到数据仓库分析系统，用于统计分析；<br />
l  个人订单查询，前后台都有；<br />
l  购物记录查询显示；</p>
<p><strong>根据业务规则描述需要使用操纵数据的<acronym title="Structured Query Language">SQL</acronym>语句</strong><br />
(1).      EXPLAIN SELECT * FROM goods_order WHERE `order_id`=40918986;<br />
(2).      SELECT * FROM goods_order WHERE `order_id` IN (40918986,40717328,30923040…) ORDER BY gmt_modify DESC;<br />
(3).      UPDATE goods_order SET gmt_modify=NOW(),…. WHERE  `order_id`=40717328 AND goods_id=4248;<br />
(4).      SELECT COUNT(*) FROM goods_order WHERE depot_id=0 ORDER BY gmt_modify DESC LIMIT 0,50;<br />
(5).      SELECT * FROM goods_order WHERE depot_id=6 AND packet_id=0 ORDER BY gmt_modify DESC LIMIT 0,50;<br />
(6).      SELECT COUNT(*) FROM goods_order WHERE goods_id=4248 AND order_status=0 AND order_type=1<br />
(7).      SELECT * FROM goods_order WHERE goods_id=4248 AND order_status=0 AND order_type=1 ORDER BY gmt_modify DESC LIMIT 0,50;<br />
(8).      SELECT * FROM goods_order WHERE gmt_modify&gt;=’ 2011-04-06’;<br />
8条<acronym title="Structured Query Language">SQL</acronym>语句按触发其执行的用户分类：<br />
l   前台用户点击触发的操作而会执行的<acronym title="Structured Query Language">SQL</acronym>语句为：(1)、(2)、(3)；<br />
l   后台内部用户点击触发的操作而会执行的<acronym title="Structured Query Language">SQL</acronym>语句为：(1)、(2)、(3)、(4)、(5)、(6)、(7)；<br />
l   后台系统自动定期执行：(4)、(5)、(6)、(7)，工作时间正常情况每隔15分钟执行一次，以检查是否有已付款而没有准备货物的订单、是否有收款而未发货的订单等;<br />
l  统计分析系统定期导出数据而执行的<acronym title="Structured Query Language">SQL</acronym>语句为：(8)，频率为每24小时一次；<br />
我们再分析上述列出来的<acronym title="Structured Query Language">SQL</acronym>，分为2类，一类是读操作的<acronym title="Structured Query Language">SQL</acronym>（备注：SELECT操作），另外一类为修改性操作（备注：UPDATE、DELETE操作），分别如下：<br />
SELECT 的WHERE子句、GROUP BY子、ORDER BY 子句和HAVING 子句中，出现的字段：<br />
(1).      order_id<br />
(2).      order_id+gmt_modify<br />
(3).      depot_id+gmt_modify<br />
(4).      depot_id+packet_id+gmt_modify<br />
(5).      goods_id+order_status+order_type<br />
(6).      goods_id+order_status+order_type+gmt_modify<br />
(7).      gmt_modify<br />
修改性操作的WHERE子句中出现的条件字段：<br />
(8).     order_id+ goods_id</p>
<p>我们已经存在主键索引：PRIMARY KEY(order_id,`goods_id`)，另外考虑到此表数据的操作以SELECT和INSERT为主，UPDATE的<acronym title="Structured Query Language">SQL</acronym>量其次，再根据上述<acronym title="Structured Query Language">SQL</acronym>语句，为此我们可以初步确定需要创建的索引：<br />
ALTER TABLE goods_order<br />
ADD INDEX idx_goodsID_orderType_orderStatus_gmtmodify(goods_id,order_type,order_status,gmt_modify),<br />
ADD INDEX idx_depotID_packetID_gmtmodify(depot_id,packet_id,gmt_modify);</p>
<p>总结：<br />
文章中也分析了为何联合主键索引的顺序为：order_id,`goods_id`，再补充下作为主键的联合索引的字段属性的其他特性：字段值写入之后不变化、字段值长度短且最好为数值类型；<br />
对于编号<acronym title="Structured Query Language">SQL</acronym>：(8)，每天按更新日期读取一次数据的操作，以采用全表扫描的方式实现，牺牲其数据读取的性能，以减少更新字段修改日期的值而带来的索引维护开销；<br />
对于编号<acronym title="Structured Query Language">SQL</acronym>：(4)、(5)，考虑到每次都是读取最新的５０条记录，以及读取的数据基本上可肯定为热数据，为此不得不牺牲其中一条<acronym title="Structured Query Language">SQL</acronym>的数据读取性能，而少创建一个联合索引，从而减少维护索引字段的IO量；<br />
对于编号<acronym title="Structured Query Language">SQL</acronym>：(6)、(7)，创建的联合索引，需要特别注意联合索引：idx_goodsID_orderType_orderStatus_gmtmodify(goods_id,order_type,order_status,gmt_modify)中的字段顺序，其中：<br />
l   goods_id字段的筛选率高于order_type,order_status，另外gmt_modify字段只出现在ORDER BY子句中，为此只有让goods_id字段作为联合索引的头部，以提高索引的筛选率，从而提高索引的效率，减少逻辑或物理的读。<br />
l   order_status字段只有0或1两种值，而order_type有多种，以及根据<acronym title="Structured Query Language">SQL</acronym>语句，必须order_type出现在联合中的位置要比order_status靠近头部；<br />
l   gmt_modify字段出现在ORDER BY子句中，为此必须放到联合索引字段的最后；</p>
<p>最后，再梳理一下从需求到设计存储结构，再到编写<acronym title="Structured Query Language">SQL</acronym>和创建索引结构，我们应该做的步骤：<br />
l   整理业务产生的数据流，读取数据的方式；<br />
l   整理清楚数据流中的每个数据项属性信息；<br />
l   分析业务指标，推测需要存储数据的规模（备注：一定要以多少<acronym title="Gigabyte">GB</acronym>作为容量单位）；<br />
l   选择可能用于支持业务的硬件设备和数据库架构；<br />
l   把所有可能操纵数据的条件和操作类型，都整理清楚；<br />
l   分析操纵数据条件字段各自的数据筛选率；<br />
l   权衡各个<acronym title="Structured Query Language">SQL</acronym>的性能和IO量，也即类似于哪个操作权重高一些，那些操作权重适当低一些；<br />
l   创建索引组织结构；<br />
l   收集测试和生产环境的反馈信息，优化索引组织结构；</p>
<p>备注：<br />
本想再用测试环境结合业务的方式，跑一套模拟测试脚本程序，让大家更加直观地看到不同索引组织情况下，相同的<acronym title="Structured Query Language">SQL</acronym>操作及频率，数据库服务器的处理能力和负载变化及对比信息，可惜唯一的服务器无法使用了，只好放弃。对于分析相同的<acronym title="Structured Query Language">SQL</acronym>，走不通索引，其需要的逻辑IO和物理IO量也是一个办法，此次就不分析了，有需要的朋友可以去玩玩，另外建议初学者一定要好好阅读下mysql 手册上的相关章节内容：7.2.6. Index Merge Optimization。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2010年03月20日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html" title="MySQL索引与存储方式对性能的影响">MySQL索引与存储方式对性能的影响</a> (2)</li><li>2009年12月21日 -- <a href="http://www.penglixun.com/tech/database/mysql_virtual_function_index.html" title="给MySQL做虚拟的“函数索引”">给MySQL做虚拟的“函数索引”</a> (0)</li><li>2009年11月10日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_check_script_preview.html" title="MySQL索引检查脚本预览">MySQL索引检查脚本预览</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL索引与存储方式对性能的影响</title>
		<link>http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html#comments</comments>
		<pubDate>Sat, 20 Mar 2010 09:27:13 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[Index]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[myisam]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1077</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html 本文配图来自《高性能M... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html </p>
<p></span>本文配图来自《高性能MySQL(第二版)》。</p>
<p>在数据库中，对性能影响最大的几个策略包括数据库的锁策略、缓存策略、索引策略、存储策略、执行计划优化策略。<br />
索引策略决定数据库快速定位数据的效率，存储策略决定数据持久化的效率。<br />
MySQL中两大主要存储引擎MyISAM和InnoDB采用了不同的索引和存储策略，本文将分析它们的异同和性能。</p>
<p>MySQL主要提供2种方式的索引：B-Tree（包括B+Tree）索引，Hash索引。<br />
B树索引具有范围查找和前缀查找的能力，对于N节点的B树，检索一条记录的复杂度为O(LogN)。<br />
哈希索引只能做等于查找，但是无论多大的Hash表，查找复杂度都是O(1)。<br />
显然，如果值的差异性大，并且以等于查找为主，Hash索引是更高效的选择，它有O(1)的查找复杂度。如果值的差异性相对较差，并且以范围查找为主，B树是更好的选择，它支持范围查找。</p>
<p><span id="more-1077"></span><br />
Hash索引各种引擎大同小异，没有太多可探讨性，本文主要讨论不同形式的B树索引。</p>
<p>B树属于二叉平衡树，平衡树就是任何一个节点的左右节点高度差距不能超过1的树，这才是绝对平衡的树。<br />
平衡树比较好的算法是AVL，它通过左旋、右旋及其组合的操作可以保证树绝对平衡。<br />
下面是AVL算法中的全部旋转操作：<br />
<a title="Flickr 上 P.Linux 的 AVL二叉平衡树" href="http://www.flickr.com/photos/penglixun/4446760301/"><img src="http://farm5.static.flickr.com/4024/4446760301_da13d53506_o.jpg" alt="AVL二叉平衡树" width="435" height="727" /></a><br />
平衡树处在任何一个左边的不平衡状态都可以通过相应的旋转操作转移到右边的平衡状态。</p>
<p>数据库采用的B树只在叶子节点记录信息，非叶子节点记录的是范围信息，这是与一般搜索树不同的地方（一般搜索树非叶子节点也记录信息）。<br />
这是一个B+树的结构，InnoDB的索引都采取了这种形式，它在B-树的基础上为每个叶子节点加了一个指针指向下一个叶子节点，这样可以快速的进行范围查找。<br />
MyISAM是否也是B+树我还不能确定，但是B-树我没有想到可以快速进行范围查找的方法，应该也是B+树。<br />
<a title="Flickr 上 P.Linux 的 B+树索引" href="http://www.flickr.com/photos/penglixun/4445202603/"><img src="http://farm5.static.flickr.com/4029/4445202603_eb376f2d2b_o.png" alt="B+树索引" width="544" height="355" /></a></p>
<p>例如这个B+树的例子：<br />
<a title="Flickr 上 P.Linux 的 B+树索引的例子" href="http://www.flickr.com/photos/penglixun/4445202745/"><img src="http://farm5.static.flickr.com/4007/4445202745_f95863b2b4_o.png" alt="B+树索引的例子" width="543" height="368" /></a><br />
如果我要查找名字以A开头的全部信息，我只要获取第一个叶子节点，然后顺序沿着指向下一个叶子的指针，直到发现当年叶子节点已经不是以A开头则中止，这样只要搜索到第一个叶子节点(O(LogN))再沿着指针检索(O(N))，就可以获取全部索引，如果N个节点的表扫描M个连续值，就是O(LogN)+O(M)，如果B-树则需要回溯到上层节点，这样最差的效率是O(LogN)*M。</p>
<p>对于InnoDB，使用了一种改进的B+树索引，称为聚集索引（Clustered Index），它的不同之处在于索引上不仅有索引值的信息，还有整个索引值所在行的信息，免去了一次通过索引值上的位置去取整行的操作。<br />
<a title="Flickr 上 P.Linux 的 聚集索引" href="http://www.flickr.com/photos/penglixun/4445976712/"><img src="http://farm3.static.flickr.com/2789/4445976712_08522430fe_o.png" alt="聚集索引" width="546" height="398" /></a></p>
<p>假设我们有个表有(col1,col2)列，col1是主键，col2也建立索引。那么在MyISAM引擎中，文件会被这样记录，因为MyISAM是按插入顺序把数据写入文件。如果有删除则空出位置，再次插入如果可以放下则会填充空白，对于不定长的行，存储引擎都会在分页中预留位置，以供更新更长的值（一般是VARCHAR），放不下则会添加到文件结尾，并从原位置删除。所以有时候会有空间浪费，需要Optimize Table来优化。<br />
因此：<span style="color: #ff0000;">定长的行比不定长的行效率高！把定长数据和不定长数据分开存储，很多时候可以提高效率。</span><br />
<a title="Flickr 上 P.Linux 的 MyISAM的文件组织" href="http://www.flickr.com/photos/penglixun/4445976822/"><img src="http://farm5.static.flickr.com/4026/4445976822_5d91f2511e_o.png" alt="MyISAM的文件组织" width="206" height="176" /></a></p>
<p>再来看MyISAM的主键索引，索引Key是主键值，索引Value是行的文件位置，通过这个位置可以直接读取行。从这个图上来看，MyISAM也是采用B+树。<br />
<a title="Flickr 上 P.Linux 的 MyISAM主键索引结构" href="http://www.flickr.com/photos/penglixun/4445203107/"><img src="http://farm3.static.flickr.com/2716/4445203107_3c3fac95a5_o.png" alt="MyISAM主键索引结构" width="535" height="198" /></a></p>
<p>MyISAM的非主键索引，跟逐渐索引没有不同，也是索引行的文件位置。<br />
<a title="Flickr 上 P.Linux 的 MyISAM普通列索引结构" href="http://www.flickr.com/photos/penglixun/4445203165/"><img src="http://farm3.static.flickr.com/2771/4445203165_5c03c4f603_o.png" alt="MyISAM普通列索引结构" width="540" height="201" /></a></p>
<p>再看InnoDB的主键索引，索引Key是主键值，索引Value是整行的数据。<br />
<a title="Flickr 上 P.Linux 的 InnoDB主键索引结构" href="http://www.flickr.com/photos/penglixun/4445203293/"><img src="http://farm5.static.flickr.com/4072/4445203293_8e9210300b_o.png" alt="InnoDB主键索引结构" width="544" height="251" /></a></p>
<p>InnoDB的非主键索引，索引Key是列值，索引Value是主键值。<br />
<a title="Flickr 上 P.Linux 的 InnoDB普通列索引结构" href="http://www.flickr.com/photos/penglixun/4445977156/"><img src="http://farm3.static.flickr.com/2679/4445977156_3e858ec65e_o.png" alt="InnoDB普通列索引结构" width="543" height="203" /></a></p>
<p>对比MyISAM和InnoDB的索引策略：<br />
<a title="Flickr 上 P.Linux 的 聚集索引和非聚集索引对比" href="http://www.flickr.com/photos/penglixun/4445977248/"><img src="http://farm5.static.flickr.com/4060/4445977248_2e51afe688_o.png" alt="聚集索引和非聚集索引对比" width="544" height="463" /></a><br />
可以发现MyISAM所有列的索引都是一样，索引Key是列值，索引Value是行的文件位置。<br />
InnoDB的主键索引包含了行的全部信息，索引Key是主键值，索引Value是整行的值。而非主键索引索引Key是列值，索引Value是主键值，取数据时到主键索引中取。</p>
<p>并且在InnoDB中，一个聚集索引是必须的，如果没有定义主键，InnoDB也会自己隐含的建立一个聚集索引作为主键，因为InnoDB的主键索引还有个重要的功能就是行锁，这在我的<a href="http://www.penglixun.com/work/database/innodb_next_key_locking.html">另一篇文章</a>中分析过。</p>
<p>再来看看我们插入值时会发生什么：<br />
<a title="Flickr 上 P.Linux 的 插入连续值到聚集索引" href="http://www.flickr.com/photos/penglixun/4445203565/"><img src="http://farm5.static.flickr.com/4006/4445203565_08b3ff0b6c_o.png" alt="插入连续值到聚集索引" width="545" height="164" /></a><br />
InnoDB会按主键索引顺序组织文件，如果按主键顺序插入，可以直接在最尾部加入。并且只填充页面的15/16，这样可以预留部分空间以供行修改，这样组织的数据是非常紧凑的。</p>
<p>如果主键不是顺序的，我们来看看会发生什么，因为要按主键顺序存放，数据会被不断地移动，调整页面。<br />
<a title="Flickr 上 P.Linux 的 插入非连续值到聚集索引" href="http://www.flickr.com/photos/penglixun/4445977554/"><img src="http://farm5.static.flickr.com/4045/4445977554_94e9bef209_o.png" alt="插入非连续值到聚集索引" width="540" height="386" /></a><br />
所以：<span style="color: #ff0000;">InnoDB引擎按主键顺序插入记录是非常必要的，否则性能将会面临很大风险。</span></p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2009年09月30日 -- <a href="http://www.penglixun.com/tech/database/mysql_parameter_tuning.html" title="MySQL参数调优">MySQL参数调优</a> (0)</li><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Oracle的索引类型</title>
		<link>http://www.penglixun.com/tech/database/oracle_index_type.html</link>
		<comments>http://www.penglixun.com/tech/database/oracle_index_type.html#comments</comments>
		<pubDate>Thu, 31 Dec 2009 03:13:58 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[Index]]></category>
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=860</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/oracle_index_type.html 荣耀属于：Tomas Zhang 逻辑上： Single co... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/oracle_index_type.html </p>
<p></span>荣耀属于：<a href="http://tomszrp.itpub.net/">Tomas Zhang</a></p>
<p><strong>逻辑上：</strong></p>
<ul>
<li> Single column 单行索引</li>
<li> Concatenated 多行索引</li>
<li> Unique 唯一索引</li>
<li> NonUnique 非唯一索引</li>
<li> Function-based函数索引</li>
<li> Domain 域索引</li>
</ul>
<p><strong>物理上：</strong></p>
<ul>
<li> Partitioned 分区索引</li>
<li> NonPartitioned 非分区索引</li>
<li> B-tree：
<ul>
<li> Normal 正常型B树</li>
<li> Rever Key 反转型B树</li>
<li> Bitmap 位图索引</li>
</ul>
</li>
</ul>
<p><strong>索引结构：</strong></p>
<ul>
<li> B-tree：
<ul>
<li> 适合与大量的增、删、改（OLTP）；</li>
<li> 不能用包含OR操作符的查询；</li>
<li> 适合高基数的列（唯一值多）；</li>
<li> 典型的树状结构；</li>
<li> 每个结点都是数据块；</li>
<li> 大多都是物理上一层、两层或三层不定，逻辑上三层；</li>
<li> 叶子块数据是排序的，从左向右递增；</li>
<li> 在分支块和根块中放的是索引的范围；</li>
</ul>
</li>
<li> Bitmap：
<ul>
<li> 适合与决策支持系统；</li>
<li> 做UPDATE代价非常高；</li>
<li> 非常适合OR操作符的查询；</li>
<li> 基数比较少的时候才能建位图索引；</li>
</ul>
</li>
</ul>
<p><strong>树型结构：</strong></p>
<ul>
<li> 索引头：
<ul>
<li>开始ROWID，结束ROWID（先列出索引的最大范围）；</li>
</ul>
</li>
<li> BITMAP：
<ul>
<li>每一个BIT对应着一个ROWID，它的值是1还是0，如果是1，表示着BIT对应的ROWID有值；</li>
</ul>
</li>
</ul><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2011年06月2日 -- <a href="http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html" title="MySQL中创建及优化索引组织结构的思路">MySQL中创建及优化索引组织结构的思路</a> (0)</li><li>2010年03月20日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html" title="MySQL索引与存储方式对性能的影响">MySQL索引与存储方式对性能的影响</a> (2)</li><li>2010年01月9日 -- <a href="http://www.penglixun.com/tech/database/oel_install_iscsi_rac_record.html" title="在OEL5.4上安装Oracle 10g R2 x64 RAC的一些记录">在OEL5.4上安装Oracle 10g R2 x64 RAC的一些记录</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/oracle_index_type.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>给MySQL做虚拟的“函数索引”</title>
		<link>http://www.penglixun.com/tech/database/mysql_virtual_function_index.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql_virtual_function_index.html#comments</comments>
		<pubDate>Mon, 21 Dec 2009 08:27:02 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[Index]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[函数索引]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=849</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql_virtual_function_index.html 对于带有列的函数计算的SQL... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql_virtual_function_index.html </p>
<p></span>对于带有列的函数计算的<acronym title="Structured Query Language">SQL</acronym>，MySQL是无法使用索引的，MySQL并没有Oracle中的函数索引，<br />
例如：</p>

<div class="wp_codebox"><table><tr id="p84910"><td class="code" id="p849code10"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span>
<span style="color: #993333; font-weight: bold;">FROM</span> table_1
<span style="color: #993333; font-weight: bold;">WHERE</span> func_1<span style="color: #66cc66;">&#40;</span>col_1<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&lt;</span> const_1
<span style="color: #993333; font-weight: bold;">AND</span>  func_2<span style="color: #66cc66;">&#40;</span>col_2<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">=</span> const_2
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> func_1<span style="color: #66cc66;">&#40;</span>col_1<span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<p><span id="more-849"></span></p>
<p>在Oracle中，我们可以建里组合函数索引：</p>

<div class="wp_codebox"><table><tr id="p84911"><td class="code" id="p849code11"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> idx_1 <span style="color: #993333; font-weight: bold;">ON</span> table_1 <span style="color: #66cc66;">&#40;</span> func_2<span style="color: #66cc66;">&#40;</span>col_2<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> func_1<span style="color: #66cc66;">&#40;</span>col_1<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<p>但是在MySQL中，没有提供函数索引，怎么办？就此罢休？存在这样的需求，就得去解决，遂想到使用冗余+触发器来虚拟函数索引。<br />
首先，利用新列来存储函数计算的结果，增加col_1_f1，col_2_f2两个列分别存储col_1/col_2的函数计算结果，然后写2个触发器，分别处理INSERT和UPDATE的情况。</p>

<div class="wp_codebox"><table><tr id="p84912"><td class="code" id="p849code12"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> trg_f1 BEFORE <span style="color: #993333; font-weight: bold;">UPDATE</span>
<span style="color: #993333; font-weight: bold;">ON</span> verycd  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW
BEGIN
    <span style="color: #993333; font-weight: bold;">SET</span> NEW<span style="color: #66cc66;">.</span>col_1_f1<span style="color: #66cc66;">=</span>func_1<span style="color: #66cc66;">&#40;</span>NEW<span style="color: #66cc66;">.</span>col_1<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #993333; font-weight: bold;">SET</span> NEW<span style="color: #66cc66;">.</span>col_2_f2<span style="color: #66cc66;">=</span>func_2<span style="color: #66cc66;">&#40;</span>NEW<span style="color: #66cc66;">.</span>col_2<span style="color: #66cc66;">&#41;</span>;
END;
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> trg_f1 BEFORE <span style="color: #993333; font-weight: bold;">INSERT</span>
<span style="color: #993333; font-weight: bold;">ON</span> verycd  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW
BEGIN
    <span style="color: #993333; font-weight: bold;">SET</span> NEW<span style="color: #66cc66;">.</span>col_1_f1<span style="color: #66cc66;">=</span>func_1<span style="color: #66cc66;">&#40;</span>NEW<span style="color: #66cc66;">.</span>col_1<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #993333; font-weight: bold;">SET</span> NEW<span style="color: #66cc66;">.</span>col_2_f2<span style="color: #66cc66;">=</span>func_2<span style="color: #66cc66;">&#40;</span>NEW<span style="color: #66cc66;">.</span>col_2<span style="color: #66cc66;">&#41;</span>;
END;</pre></td></tr></table></div>

<p>然后我们对col_1_f1，col_2_f2两个列建索引：</p>

<div class="wp_codebox"><table><tr id="p84913"><td class="code" id="p849code13"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> idx_1 <span style="color: #993333; font-weight: bold;">ON</span> table_1 <span style="color: #66cc66;">&#40;</span> col_2_f2，col_1_f1 <span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<p>将查询语句改为：</p>

<div class="wp_codebox"><table><tr id="p84914"><td class="code" id="p849code14"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span>
<span style="color: #993333; font-weight: bold;">FROM</span> table_1
<span style="color: #993333; font-weight: bold;">WHERE</span> col_1_f1 <span style="color: #66cc66;">&lt;</span> const_1
<span style="color: #993333; font-weight: bold;">AND</span>  col_2_f2 <span style="color: #66cc66;">=</span> const_2
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> col_1_f1;</pre></td></tr></table></div>

<p>这就实现了虚拟的“函数索引”，从这样看函数索引的实现并不复杂，MySQL只要在B-Tree中记录函数计算后的结果作为建树关键字就能实现，不知道MySQL为什么不做呢？<br />
欢迎拍砖~</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2011年06月2日 -- <a href="http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html" title="MySQL中创建及优化索引组织结构的思路">MySQL中创建及优化索引组织结构的思路</a> (0)</li><li>2010年03月20日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html" title="MySQL索引与存储方式对性能的影响">MySQL索引与存储方式对性能的影响</a> (2)</li><li>2009年11月10日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_check_script_preview.html" title="MySQL索引检查脚本预览">MySQL索引检查脚本预览</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql_virtual_function_index.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL索引检查脚本预览</title>
		<link>http://www.penglixun.com/tech/database/mysql_index_check_script_preview.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql_index_check_script_preview.html#comments</comments>
		<pubDate>Tue, 10 Nov 2009 07:55:43 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[Index]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/PLX/Blog/?p=530</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql_index_check_script_preview.html 工作比较忙，还没整太多... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql_index_check_script_preview.html </p>
<p></span>工作比较忙，还没整太多，暂时还没有把各个分析模块整合起来。<br />
支持分析远程数据库索引，主要根据唯一性和业务中的使用情况进行分析，全功能使用需要general日志或者慢查日志，最好是General日志这样会考虑进表被修改的影响，分析结果要准确一些。<br />
分析结果如下方式输出，包括表中一共包含的记录条数，可能没用的索引，以及无用索引的条数等。<br />
鉴于目前分析结果还不能自动化，需要人工判断，只是帮我提高了一些效率，暂不放出代码，等能胜任生产环境我再放出代码。</p>
<p>|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
|Table backpack_hotel Have 9 Index :<br />
|	Have 362 Rows!<br />
|<br />
|backpack_hotel 	 stars 	 10<br />
|backpack_hotel 	 cat_id 	 6<br />
|backpack_hotel 	 cat_id_2 	 6<br />
|backpack_hotel 	 hotel_type 	 2<br />
|backpack_hotel 	 type 	 3<br />
|<br />
|[Have 5 Unused, 55.5555555555556 % of All!]<br />
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<span id="more-530"></span><br />
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
|Table backpack_hotel_additional Have 1 Index :<br />
|	Have 6 Rows!<br />
|<br />
|backpack_hotel_additional 	 type 	 1<br />
|<br />
|[Have 1 Unused, 0 % of All!]<br />
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
|Table backpack_hotel_cat Have 2 Index :<br />
|	Have 123 Rows!<br />
|<br />
|backpack_hotel_cat 	 type 	 1<br />
|<br />
|[Have 1 Unused, 50 % of All!]<br />
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
|Table backpack_hotel_cat_relate Have 3 Index :<br />
|	Have 283 Rows!<br />
|<br />
|<br />
|[Have 0 Unused, 0 % of All!]<br />
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2011年06月2日 -- <a href="http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html" title="MySQL中创建及优化索引组织结构的思路">MySQL中创建及优化索引组织结构的思路</a> (0)</li><li>2010年03月20日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html" title="MySQL索引与存储方式对性能的影响">MySQL索引与存储方式对性能的影响</a> (2)</li><li>2009年12月21日 -- <a href="http://www.penglixun.com/tech/database/mysql_virtual_function_index.html" title="给MySQL做虚拟的“函数索引”">给MySQL做虚拟的“函数索引”</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql_index_check_script_preview.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

