<?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>Some reminiscences, some memories &#187; Database</title>
	<atom:link href="http://www.mikespook.com/index.php/category/database/feed" rel="self" type="application/rss+xml" />
	<link>http://www.mikespook.com</link>
	<description>Just another boring day</description>
	<lastBuildDate>Tue, 10 Jan 2012 03:14:06 +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>[翻译]MongoDB：PHP开发者应该知道的关于 MongoDB 的 5 件事儿</title>
		<link>http://www.mikespook.com/2010/03/%e7%bf%bb%e8%af%91mongodb%ef%bc%9aphp%e5%bc%80%e5%8f%91%e8%80%85%e5%ba%94%e8%af%a5%e7%9f%a5%e9%81%93%e7%9a%84-5-%e4%b8%aa%e5%85%b3%e4%ba%8e-mongodb-%e7%9a%84%e4%ba%8b%e5%84%bf/</link>
		<comments>http://www.mikespook.com/2010/03/%e7%bf%bb%e8%af%91mongodb%ef%bc%9aphp%e5%bc%80%e5%8f%91%e8%80%85%e5%ba%94%e8%af%a5%e7%9f%a5%e9%81%93%e7%9a%84-5-%e4%b8%aa%e5%85%b3%e4%ba%8e-mongodb-%e7%9a%84%e4%ba%8b%e5%84%bf/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 04:04:52 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=524</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
原文：http://technosophos.com/content/mongodb-5-things-every-php-developer-should-know-about-mongodb

感觉这篇文章说了一些 MongoDB 的要点，适合 MongoDB 扫盲使用。所以翻译出来，造福于民。虽然文章是针对 PHP 开发者写的，但实际上 python、ruby 或者其他 web 开发人员也可借鉴。

&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-这里是译文分隔线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;

<span class="readmore"><a href="http://www.mikespook.com/2010/03/%e7%bf%bb%e8%af%91mongodb%ef%bc%9aphp%e5%bc%80%e5%8f%91%e8%80%85%e5%ba%94%e8%af%a5%e7%9f%a5%e9%81%93%e7%9a%84-5-%e4%b8%aa%e5%85%b3%e4%ba%8e-mongodb-%e7%9a%84%e4%ba%8b%e5%84%bf/" title="[翻译]MongoDB：PHP开发者应该知道的关于 MongoDB 的 5 件事儿">阅读全文——共2223字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>原文：<a href="http://technosophos.com/content/mongodb-5-things-every-php-developer-should-know-about-mongodb" target="_blank">http://technosophos.com/content/mongodb-5-things-every-php-developer-should-know-about-mongodb</a></p>
<p>感觉这篇文章说了一些 MongoDB 的要点，适合 MongoDB 扫盲使用。所以翻译出来，造福于民。虽然文章是针对 PHP 开发者写的，但实际上 python、ruby 或者其他 web 开发人员也可借鉴。<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-这里是译文分隔线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<span id="more-524"></span></p>
<p>2010年将被记住，因为这一年 SQL 死了；这一年关系数据库从一线退下；这一年开发人员发现他们没必要为了持久化数据，将每个对象转化为表格结构。</p>
<p>2010年是文档数据库的一年。尽管一直在稳步发展势头，通过过去七年多的发展，现在有各种稳定的文档数据库——从基于亚马逊和谷歌的云，到各种开放源码工具，尤其是 <a href="http://couchdb.apache.org/" target="_blank">CouchDB</a> 和 <a href="http://www.mongodb.org/display/DOCS/Home" target="_blank">MongoDB</a>。</p>
<p>那么，MongoDB 是什么？这里的五件事是每个 PHP 开发人员应该知道的：</p>
<p><strong>1、MongoDB 是一个独立的服务器<br />
2、它是基于文档的，而不是基于表格的<br />
3、它是非结构化的<br />
4、不必去学习另一种查询语言<br />
5、它具有强大的 PHP 支持</strong></p>
<p>阅读下文，可以了解关于这些的详细内容。</p>
<p><strong>1、MongoDB 是一个独立的服务器</strong></p>
<p>如 MySQL 或 PostgreSQL 一样，MongoDB 侦听端口以便接入。它提供了用于查询，创建，更新和删除的工具。从理论上讲，你使用它的工作方式与你使用 MySQL 或 PostgreSQL 的工作方式相同：连接，执行任务，并关闭连接。<br />
<strong><br />
2、跟行和表格说再见，向文档和集合说你好</strong></p>
<p>MongoDB 存储整个文档，代替了存储在表的行数据中。如果有一个含有标题、多位作者、内容和标签的“文章”数据，该数据基本上看起来像这样：</p>
<pre class="brush: php; title: ; notranslate">
&lt;? php
array(
    'title' =&gt; 'Hello World',
    'authors' =&gt; array('John', 'Sally', 'Jim'),
    'body' =&gt; 'Hello world',
    'tags' =&gt; array('tag1', 'tag2', 'tag3')
);
?&gt;
</pre>
<p>要注意的关键，上面的例子是一个记录——一个文档——实际上是像文档一样存储，并支持同一字段有多个值的情况。没有必要将数据转化为通常意义上的表中，因为，根本没有表。</p>
<p>现在，作为将文档存储在表中的替代方案，它们存储在一个集合里，这可以认为是一个大的文档列表。</p>
<p><strong>3、MongoDB 是非结构化的</strong></p>
<p>MongoDB 没有结构化语言。如果你想创建一个新的文档类型，你不用做任何事来告诉数据库关于这些数据的结构，而仅仅是存到数据库中即可。</p>
<p>在第 2 点中，我虚构了一个文档。现在，如果我想在这些字段上定义文章类型，我所要做的仅仅是存储对象到数据库如果我想定义它与这些领域的文章类型，首先，我需要做的就是写入数据库中的对象。日后，如果我决定增加一些什么，例如，一个日期？我只是从数据库中获得文章，添加日期字段，并保存它。</p>
<p>相关的数据类型是什么？简单的说，MongoDB 使用类似 JavaScript 或 PHP 的类型处理方式。也就是说，数据库是灵活的弱类型。</p>
<p>虽然有一些数据是有限制条件的（大块的数据可能需要一些明确的处理），但在大多数情况下，你可以像写 PHP 代码一样编写你的 MongoDB 代码。</p>
<p><strong>4、不必去学习另一种查询语言！</strong></p>
<p>还记得这些你写的数据库抽象层吗？还记得那些你处理过的 ORM 层吗？现在，你可以将它们全部丢弃。在 Mongo 中你不需要他们。</p>
<p>MongoDB（当使用 PHP 驱动）没有很多查询语句。在大多数情况下，只需给它一个数组指定你想要的信息，然后它会给你返回文档的数组。</p>
<p>如果你想运行一些非常复杂的查询（如Map-Reduce操作），可以向MongoDB 传递 JavaScript，其内部的 JavaScript 引擎可以解析这个脚本。</p>
<p><strong>5、PHP 和 MongoDB 是上天注定的一对搭档</strong></p>
<p>PHP 已经有很好的 MongoDB 支持。Mongo 驱动可以通过 PECL 扩展安装到 PHP，这意味着运行 pecl 安装 mongo 非常简单。（早些时候我写了一篇短文，详细介绍了<a href="http://technosophos.com/content/os-x-installing-mongodb-and-php-mongo-driver" target="_blank">安装过程</a>）</p>
<p>然后，你可以立即使用<a href="http://us2.php.net/manual/en/book.mongo.php" target="_blank"> Mongo 的 API</a> 开始工作。复杂性，站在 PDO 的阵营中。它不够简单，<del datetime="2010-03-24T01:00:36+00:00">but there should be nothing foreign about it for anyone who has done database development before.（注：不知道怎么翻译，不是关键，大家自悟吧）</del>但是这对于之前做过数据库开发的人来说，不会很陌生。</p>
<p>API 文档（上面有连接）包括了指引和许多例子，所以你应该能够在一个很短的时间里学会。这里有一些你需要注意的：</p>
<p>* MongoDB 是神速的<br />
* 开发时间也短，因为没有结构需要管理，和很少（如果有的话）的数据映射。<br />
* 学习曲线很平滑，因为没有新的查询语言学习。<br />
* 代码是简洁的。毕竟，无须任何其他 ORM，封装可以非常简单。<br />
* 你的代码是未来的保证。向你的对象增加更多的字段是很轻松的——甚至复杂的字段。因此，需求变化了，你可以很快修改代码以便适应。</p>
<p>我用 MongoDB 开发只有一段时间，但这足以让我意识到它有改变游戏规则的潜力。这也是让我主张使用新一代的文档数据库代替基于 SQL 的关系数据库的原因。将关系数据库留在尘土里——或者，更可能的是让它们做它们能做好的事情：存数属于行和表的数据。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2010/03/%e7%bf%bb%e8%af%91mongodb%ef%bc%9aphp%e5%bc%80%e5%8f%91%e8%80%85%e5%ba%94%e8%af%a5%e7%9f%a5%e9%81%93%e7%9a%84-5-%e4%b8%aa%e5%85%b3%e4%ba%8e-mongodb-%e7%9a%84%e4%ba%8b%e5%84%bf/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Mysql 性能改进——最快实践</title>
		<link>http://www.mikespook.com/2009/06/mysql-%e6%80%a7%e8%83%bd%e6%94%b9%e8%bf%9b%e2%80%94%e2%80%94%e6%9c%80%e5%bf%ab%e5%ae%9e%e8%b7%b5/</link>
		<comments>http://www.mikespook.com/2009/06/mysql-%e6%80%a7%e8%83%bd%e6%94%b9%e8%bf%9b%e2%80%94%e2%80%94%e6%9c%80%e5%bf%ab%e5%ae%9e%e8%b7%b5/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 05:10:01 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=361</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
没错，标题我没打错。这里不是最佳实践，而是最快实践。在服务器上线，巨大的压力导致相应缓慢的时候，最佳实践已经毫无意义。这个时候，目的只有一个：最快改善性能，给开发人员重新设计、调整应用留出一定的时间。

这里不是细腻的微调，而是最粗旷的拉升。用最简单（可快速实施），变更最少（尽量避免变更引入新的 bug 和问题）的方法迅速改善 mysql 的性能。所以我这里的最快实践，不一定是最好的，不一定是最有效的，但是一定是最快能看到性能改善的方法。

tmp_table_size

<span class="readmore"><a href="http://www.mikespook.com/2009/06/mysql-%e6%80%a7%e8%83%bd%e6%94%b9%e8%bf%9b%e2%80%94%e2%80%94%e6%9c%80%e5%bf%ab%e5%ae%9e%e8%b7%b5/" title="Mysql 性能改进——最快实践">阅读全文——共1489字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>没错，标题我没打错。这里不是最佳实践，而是最快实践。在服务器上线，巨大的压力导致相应缓慢的时候，最佳实践已经毫无意义。这个时候，目的只有一个：最快改善性能，给开发人员重新设计、调整应用留出一定的时间。</p>
<p>这里不是细腻的微调，而是最粗旷的拉升。用最简单（可快速实施），变更最少（尽量避免变更引入新的 bug 和问题）的方法迅速改善 mysql 的性能。所以我这里的最快实践，不一定是最好的，不一定是最有效的，但是一定是最快能看到性能改善的方法。<span id="more-361"></span></p>
<h1>tmp_table_size</h1>
<p>实施难度：容易</p>
<p>实施时间：短</p>
<p>实施效果：明显</p>
<p>tmp_table_size 默认 32M，根据手册上的说法，这个限制了内存临时表的大小。增大这个值可以立刻改善 mysql 的性能，虽然不是万灵丹，但却是个救命药。网上解释很多不多说了。</p>
<h1>thread_cache_size</h1>
<p>实施难度：容易</p>
<p>实施时间：短</p>
<p>实施效果：一般</p>
<p>在使用 SHOW STATUS; 查看 mysql 参数时，如果 thread_created 这个值很高的话，可以将 thread_cache_size 设置得大一些。内存允许的情况下，128 或者更大都是可以考虑的。mysql 通过内建的线程复用机制来实现了一个连接池。如果你的应用出现 max connection 的情况话（php 发生这种情况尤为严重），还是请开启 thread_cache_size 吧。</p>
<h1>索引</h1>
<p>实施难度：一般</p>
<p>实施时间：一般</p>
<p>实施效果：明显</p>
<p>不知什么时候，有一位高人说“对于 where 查询的条件字段，都加上索引会提高查询效率”。于是大家忙不停的将所有可能的字段都加上了索引。潘多拉的魔盒从此打开……</p>
<p>上图：</p>
<p><a href="http://www.mikespook.com/wp-content/uploads/2009/06/nouse_index.JPG"><img class="size-full wp-image-362 alignnone" title="nouse_index" src="http://www.mikespook.com/wp-content/uploads/2009/06/nouse_index.JPG" alt="nouse_index" width="554" height="114" /></a></p>
<p>这样的表中，假设 t2 的总记录数不超过10 条。如果 t2_c1 这个字段有这样的查询 select * from t1 where t2_c1 = 1; 不少童鞋都会在 t2_c1 上加多一个索引，为了让这个搜索更快一些。这会是真的么？</p>
<p>显然不是！</p>
<p>在 t2_c1 字段的数据差异很小的情况下，使用索引不会比全表扫描快。更有可能的情况是，索引不但导致 t1 表数据修改变慢，同时导致查询变慢。为什么？大家先学习一下“随机存取”和“连续预读”的差异就明白了。不必要的索引还是去掉吧！我甚至见过索引比数据都大的表，如果读索引的速度比直接读数据都慢，这会有什么后果？太可怕了……</p>
<h1>只查要用到的列</h1>
<p>实施难度：大</p>
<p>实施时间：长</p>
<p>实施效果：明显</p>
<p>这绝对是老生常谈，但是总有人不在意。他们心中有疑问：“为什么？为什么？为什么 SELECT * FROM table 会慢？”他们心中有梦想：“这不可能吧，扫描的都是那么多数据，那几个表。索引使用也一样有效。”</p>
<p>的确，数据扫描的记录数不会因为列的限制而减少，索引的影响也不因为列的限制而改变。不过每个内存页面中存放记录的条数会因为列的不同发不同。为了说明这个问题，我专门构造了一个 140万条记录，每条记录大约 50字节的表。如果应用只是用结果集的主键，使用 select * from table 查询比使用 select id from table 慢了近一倍。其实道理也很简单，结果集行记录变小了，内存页面中每个页面可以放的记录数就多了。内存页面的交换就减少，I/O减少。同时采用连续预读I/O效率提高。进而查询速度提升。</p>
<p>在业务逻辑都确定的情况下，每个方法所用到的字段也都确定了。这个时候可以快速将那些没有用到的字段从查询语句中剔除。查询效率自然提升。</p>
<p>按照上面的顺序进行快速优化，可以在不改变业务逻辑和代码逻辑的情况下迅速提升 mysql 性能，同时可避免应用长时间下下线，也为进一步优化争取时间。何乐而不为？</p>
<p>如果还有更快、更好的方法，我再补充吧！</p>
<p><strong>“性能是改进出来的，不是设计出来的！”</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2009/06/mysql-%e6%80%a7%e8%83%bd%e6%94%b9%e8%bf%9b%e2%80%94%e2%80%94%e6%9c%80%e5%bf%ab%e5%ae%9e%e8%b7%b5/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MySQL InnoDB 隔离级别探索</title>
		<link>http://www.mikespook.com/2009/05/mysql-innodb-%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e6%8e%a2%e7%b4%a2/</link>
		<comments>http://www.mikespook.com/2009/05/mysql-innodb-%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e6%8e%a2%e7%b4%a2/#comments</comments>
		<pubDate>Tue, 12 May 2009 09:28:53 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[innodb]]></category>
		<category><![CDATA[isolation]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[隔离级别]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=317</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
概述

本文会简单介绍 Mysql 使用的支持事务的存储引擎 InnoDB 的隔离级别，以及每个隔离级别下回产生的并发问题。同时为了更加深刻的理解 InnoDB 引擎的隔离级别，还会探讨如何通过加锁解决不同隔离级别下的并发问题。本文使用的实验环境是 mysql-5.1.33-win32，其他版本的 MySQL 可能会有不同。

隔离级别标准

<span class="readmore"><a href="http://www.mikespook.com/2009/05/mysql-innodb-%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e6%8e%a2%e7%b4%a2/" title="MySQL InnoDB 隔离级别探索">阅读全文——共5060字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<h1>概述</h1>
<p>本文会简单介绍 Mysql 使用的支持事务的存储引擎 InnoDB 的隔离级别，以及每个隔离级别下回产生的并发问题。同时为了更加深刻的理解 InnoDB 引擎的隔离级别，还会探讨如何通过加锁解决不同隔离级别下的并发问题。本文使用的实验环境是 mysql-5.1.33-win32，其他版本的 MySQL 可能会有不同。<span id="more-317"></span></p>
<h1>隔离级别标准</h1>
<p>SQL 标准中定义了四个隔离级别，他们分别是：</p>
<div>
<table id="n15_" border="1" cellspacing="0" cellpadding="3" width="100%" bordercolor="#000000">
<tbody>
<tr>
<td width="50%">
<pre>READ-UNCOMMITTED</pre>
</td>
<td width="50%">读未提交</td>
</tr>
<tr>
<td width="50%">
<pre>READ-COMMITTED</pre>
</td>
<td width="50%">读提交</td>
</tr>
<tr>
<td width="50%">
<pre>REPEATABLE-READ</pre>
</td>
<td width="50%">可重复读</td>
</tr>
<tr>
<td width="50%">
<pre>SERIALIZABLE</pre>
</td>
<td width="50%">串行化</td>
</tr>
</tbody>
</table>
</div>
<p>在 InnoDB 中根据 SQL:1992 事务隔离级别，使用 REPEATABLE-READ 作为默认隔离级别。</p>
<h1>并发产生的问题</h1>
<p>为了说明下面的并发问题，首先建立一个表 foobar：</p>
<pre lang="SQL">DROP TABLE IF EXISTS `foobar`;
CREATE TABLE `foobar` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `value` int(10) unsigned NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB;</pre>
<p>并插入一条数据：</p>
<pre lang="SQL">INSERT INTO `foobar`(`value`) VALUES(0);</pre>
<p>为了避免隔离级别本身对并发问题的影响，需要将 MySQL 的全局隔离级别设置为最低的 READ-UNCOMMITTED：</p>
<pre lang="SQL">SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;</pre>
<p>同时为了模拟并发，下面的存储过程中使用了 SLEEP 函数，以保证语句按照预定顺序执行。</p>
<h3>脏读</h3>
<p>当两个事物并发时，事务 A 可以读到另事务 B 的中间状态的数据。若事务 B 回滚，或在之后的语句中修改了这个数据，就会有不一致的现象发生。<br />
例如，下面这两个事务：</p>
<pre lang="SQL">CREATE PROCEDURE `PROC_FOOBAR_A` ()
    BEGIN
        START TRANSACTION;
        UPDATE `foobar` SET `value`= 100 WHERE `id` = 1;
        #SELECT SLEEP(10);
        ROLLBACK;
    END</pre>
<pre lang="SQL">CREATE PROCEDURE `PROC_FOOBAR_B` ()
    BEGIN
        START TRANSACTION;
        SELECT * FROM `foobar` f WHERE `id` = 1;
        COMMIT;
    END</pre>
<p>其中，PROC_FOOBAR_A 的 SLEEP 函数的调用是为了模拟并发，让 PROC_FOOBAR_B 的语句正好在 UPDATE 和 ROLLBACK 之间执行。</p>
<p>在两个 session 中按次序执行这两个存储过程。会发现，PROC_FOOBAR_B 的查询语句读取到 id = 1 的记录中 value = 100，而在存储过程执行过后，由于 PROC_FOOBAR_B 的 ROLLBACK 语句的关系，foobar 包中 id = 1 的记录中实际 value = 0。</p>
<h3>写覆盖</h3>
<p>当两个事物并发时，事务 A 读出、运算、修改了某一个数据，事务 B 在事务 A 修改之前读出了同一份数据，在事务 A 修改之后修改了同一数据。从而造成事务 A 的修改丢失。<br />
创建下面的存储过程，使得每执行一次这个存储过程 id = 1 的 value 就增加 100：</p>
<pre lang="SQL">CREATE PROCEDURE  `PROC_FOOBAR_C`()
    BEGIN
        START TRANSACTION;
        SELECT @v:=`value` FROM `foobar` WHERE `id` = 1;
        #SELECT SLEEP(10);
        UPDATE `foobar` SET `value`= @v + 100 WHERE `id` = 1;
        COMMIT;
    END</pre>
<p>在两个不同的 session 中顺序执行两次 PROC_FOOBAR_C，由于 SLEEP 函数的存在，就保证了第二次执行的 SELECT 一定在第一次执行的查询语句之后，更新语句之前。假设初始 value = 0，由于写覆盖的存在，两次 PROC_FOOBAR_C 的执行，value 只增长了 100，而不是预期的 200。</p>
<p>实际上，由于 InnoDB 的特性，PROC_FOOBAR_C 这个存储过程即使在 SERIALIZABLE 级别下也是会产生问题的。后面会详细解释这个问题产生的原因以及对应策略。</p>
<h3>不可重复读</h3>
<p>当两个事务并发时，事务 A 读出了数据，然后事务 B 修改了数据，这时事务 A 再次读出数据时，第一次读出的数据和第二次读出的数据不一致。</p>
<p>创建下面的存储过程：</p>
<pre lang="SQL">CREATE PROCEDURE `PROC_FOOBAR_D` ()
    BEGIN
        START TRANSACTION;
        SELECT `value` FROM `foobar` WHERE `id` = 1;
        #SELECT SLEEP(10);
        SELECT `value` FROM `foobar` WHERE `id` = 1;
        COMMIT;
    END</pre>
<pre lang="SQL">CREATE PROCEDURE `PROC_FOOBAR_E` ()
    BEGIN
        START TRANSACTION;
        UPDATE `foobar` SET `value`= 1 WHERE `id` = 1;
        COMMIT;
    END</pre>
<p>在两个 session 中按次序执行这两个存储过程。会发现 PROC_FOOBAR_D 的两次查询结果不一致，对于一些需要复审数据的业务中这会带来严重的影响。</p>
<h3>幻像</h3>
<p>当两个事务并发时，事务 A 读出了一组数据，然后事务 B 在这组数据上进行了增加或者删除，这样就产生了幻像。</p>
<p>创建下面的存储过程：</p>
<pre lang="SQL">CREATE PROCEDURE `PROC_FOOBAR_F` ()
    BEGIN
        START TRANSACTION;
        SELECT * FROM `foobar` WHERE `value` > 100;
        #SELECT SLEEP(10);
        SELECT * FROM `foobar` WHERE `value` > 100;
        DELETE FROM `foobar` WHERE `value` > 100;
        SELECT * FROM `foobar` WHERE `value` > 100;
        COMMIT;
    END</pre>
<pre lang="SQL">CREATE PROCEDURE `PROC_FOOBAR_G` ()
    BEGIN
        START TRANSACTION;
        SELECT * FROM `foobar` WHERE `value` > 100;
        INSERT INTO `foobar` (`value`) VALUES(101),(102),(103);
        SELECT * FROM `foobar` WHERE `value` > 100;
        #SELECT SLEEP(10);
        SELECT * FROM `foobar` WHERE `value` > 100;
        COMMIT;
    END</pre>
<p>并且向表中再插入两条记录：</p>
<pre lang="SQL">INSERT INTO `foobar` (`value`) VALUES(200),(300);</pre>
<p>在两个 session 中按次序执行这两个存储过程。PROC_FOOBAR_F 在查询时在第一次查询时有 value = {200, 300}；在第二次查询时，由于 PROC_FOOBAR_G 插入了三条记录 value = {101, 102, 103}，从而得到结果 value = {200, 300, 101, 102, 103}；执行 DELETE 语句执行后，第三次查询得到空数据集。PROC_FOOBAR_G 第一次查询时得到 value = {200, 300}，第二次查询时已经插入三条记录得到 value = {200, 300, 101, 102, 103}，在 PROC_FOOBAR_F 执行了删除操作后的查询反而得到 value = {101, 102, 103}。两个存储过程在执行了删除后得到的数据产生了一个不一致现象。</p>
<p>需要说明的是，这里存在 MySQL 的 InnoDB 在处理上面的特殊性，与其他数据库产生的幻像呈现方式并不一致。</p>
<h1>不同隔离级别下可能的并发问题</h1>
<p>下表描述了四个隔离级别和并发时产生的问题之间的关系，使用以上存储过程进行测试。这里由于 InnoDB 的全局隔离级别是在设置了隔离级别之后的所有新的 session 都使用的默认隔离级别，这里为了方便起见（不用反复开启新的 session），只设置 session 的隔离级别：</p>
<pre lang="SQL">SET SESSION TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED| REPEATABLE READ | SERIALIZABLE};</pre>
<div>
<table id="nj1h" border="1" cellspacing="0" cellpadding="3" width="100%" bordercolor="#000000">
<tbody>
<tr>
<td width="20%"></td>
<td width="20%">脏读</td>
<td width="20%">写覆盖</td>
<td width="20%">不可重复读</td>
<td width="20%">幻像</td>
</tr>
<tr>
<td width="20%">
<pre>READ-UNCOMMITTED</pre>
</td>
<td width="20%">是</td>
<td width="20%">是</td>
<td width="20%">是</td>
<td width="20%">是</td>
</tr>
<tr>
<td width="20%">
<pre>READ-COMMITTED</pre>
</td>
<td width="20%">否</td>
<td width="20%">是</td>
<td width="20%">是</td>
<td width="20%">否</td>
</tr>
<tr>
<td width="20%">
<pre>REPEATABLE-READ</pre>
</td>
<td width="20%">否</td>
<td width="20%">是</td>
<td width="20%">否</td>
<td width="20%">否</td>
</tr>
<tr>
<td width="20%">
<pre>SERIALIZABLE</pre>
</td>
<td width="20%">否</td>
<td width="20%">否（死锁）</td>
<td width="20%">否</td>
<td width="20%">否</td>
</tr>
</tbody>
</table>
</div>
<p>“是”表示会发生并发问题，“否”表示不会发生并发问题。</p>
<h3>写覆盖到底怎么了？</h3>
<p>可以发现，使用 PROC_FOOBAR_C 做写覆盖的测试时，在所有隔离级别都未能真正解决写覆盖的问题。虽然在 SERIALIZABLE 级别并未发生写覆盖，但是两个事务中必有一个因为死锁而异常中断。这是因为 InnoDB 对于 SELECT 语句处理的一些特殊性决定的。</p>
<p>InnoDB 在 READ-UNCOMMITTED、READ-COMMITTED 和 REPEATABLE-READ 级别中，未明确加锁的 SELECT 语句都使用“持续非锁定读”的查询方式，这种方式下，查询语句不对读取的表加任何锁。在事务内看到的是事务开始时刻前，所有已经提交的事务的结果的快照（利用多版本的方式）。而在 SERIALIZABLE 级别，未明确加锁的 SELECT 语句被隐式转换为 SELECT &#8230; LOCK IN SHARE MODE，由于增加了共享锁（读锁），两个并发的事务发生了资源争夺，导致了死锁的发生（默认情况下，MySQL 会中断代价小的那个事务的运行，通常是后执行的事务）。</p>
<p>为了验证这点，对 PROC_FOOBAR_C 做如下修改：</p>
<pre lang="SQL">CREATE PROCEDURE `PROC_FOOBAR_C_1`()
    BEGIN
        START TRANSACTION;
        SELECT @v:=`value` FROM foobar WHERE `id` = 1 LOCK IN SHARE MODE;
        #SELECT SLEEP(5);
        UPDATE `foobar` SET `value`= @v + 100 WHERE `id` = 1;
        COMMIT;
    END</pre>
<p>用同样的方式测试写覆盖，会发现在所有隔离级别下，都会发生死锁。</p>
<p>虽然通过加共享锁的方式解决了写覆盖的问题，但是每次都使用了死锁的方式来避免。这对于一个应用系统来说是很不好的，需要额外增加很多错误处理。</p>
<p>那么让事务真正可序列化的方法是加排他锁（写锁）：</p>
<pre lang="SQL">CREATE PROCEDURE `PROC_FOOBAR_C_2`()
    BEGIN
        START TRANSACTION;
        SELECT @v:=`value` FROM foobar WHERE `id` = 1 FOR UPDATE;
        #SELECT SLEEP(5);
        UPDATE `foobar` SET `value`= @v + 100 WHERE `id` = 1;
        COMMIT;
    END</pre>
<p>使用这种方式，可以让两个并发的事务执行，通过其中一个事务等待，而变成顺序执行（序列化执行）。也就真正解决了在 MySQL 的 InnoDB 引擎中的写覆盖问题。</p>
<h3>幻像是怎么样解决的？</h3>
<p>而对于幻像或者说幽灵问题，InnoDB 使用 Next-Key 锁定<del datetime="2009-05-12T15:10:34+00:00">，通俗的说也就是对索引加锁（谓词锁）</del>。Next-Key 锁定是联合了记录锁和间隙锁的一个锁形式，通常也被称作谓词锁。记录锁是指加在索引记录上的锁。间隙锁是指加在索引记录之间的缝隙、第一条记录前或最后一条记录后的锁。（基于<a href="http://www.mikale.org/" target="_blank">路神</a>的建议，这里采用更加严谨的方式来描述。）特别值得说明的是，在手册上有这样的描述：InnoDB对索引记录设置的锁定也映像索引记录之前的“间隙”。如果一个用户对一个索引上的记录R有共享或独占的锁定，另一个用户 不能紧接在R之前以索引的顺序插入一个新索引记录。说明 Next-Key 锁在记录上存在共享或独占锁时生效。由于 READ-UNCOMMITTED 级别实际上是不加任何锁的，所以 Next-Key 锁定并不在该级别生效。</p>
<h1>请帮助我</h1>
<p>本文是为了完成高级数据库这门课的学期作业“默认隔离级别下写覆盖的处理”而编写。但在实验过程中发现 InnoDB 并没有像 SQL Server 那样使用 READ-COMMITTED 作为默认隔离级别，同时对于查询和加锁方式也有不同。觉得有必要仔细探索一下 InnoDB 引擎的隔离级别，以及各个隔离级别下并发问题的处理方式。如果我在实验中有什么遗漏或者错误，务必请指出！谢谢！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2009/05/mysql-innodb-%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e6%8e%a2%e7%b4%a2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>MYSQL 存储过程中，中文变量出现乱码的解决办法</title>
		<link>http://www.mikespook.com/2008/03/mysql-%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e4%b8%ad%ef%bc%8c%e4%b8%ad%e6%96%87%e5%8f%98%e9%87%8f%e5%87%ba%e7%8e%b0%e4%b9%b1%e7%a0%81%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/</link>
		<comments>http://www.mikespook.com/2008/03/mysql-%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e4%b8%ad%ef%bc%8c%e4%b8%ad%e6%96%87%e5%8f%98%e9%87%8f%e5%87%ba%e7%8e%b0%e4%b9%b1%e7%a0%81%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/#comments</comments>
		<pubDate>Thu, 20 Mar 2008 03:30:21 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[乱码]]></category>
		<category><![CDATA[存储过程]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/index.php/archives/105</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
昨天下班前发现有个存储过程有问题，无法正确的查询数据。

数据表和字段都是 utf8 存储的中文内容。在连接数据库后也使用 SET NAMES utf8; 设置了编码。但是在存储过程中无法查询中文内容的字段。由于一些逻辑处理的原因，存储过程使用了游标，同时定义了一些局部变量。



<span class="readmore"><a href="http://www.mikespook.com/2008/03/mysql-%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e4%b8%ad%ef%bc%8c%e4%b8%ad%e6%96%87%e5%8f%98%e9%87%8f%e5%87%ba%e7%8e%b0%e4%b9%b1%e7%a0%81%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/" title="MYSQL 存储过程中，中文变量出现乱码的解决办法">阅读全文——共695字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>昨天下班前发现有个存储过程有问题，无法正确的查询数据。</p>
<p>数据表和字段都是 utf8 存储的中文内容。在连接数据库后也使用 SET NAMES utf8; 设置了编码。但是在存储过程中无法查询中文内容的字段。由于一些逻辑处理的原因，存储过程使用了游标，同时定义了一些局部变量。</p>
<p><span id="more-105"></span></p>
<p>CREATE PROCEDURE `PROC_FOOBAR`(id INTEGER)<br />
BEGIN</p>
<p>DECLARE user_id VARCHAR(32) ;</p>
<p>&#8211; 省略代码若干</p>
<p>END</p>
<p>user_id 在代码中参与了一个 查询  SELECT  *  FROM `table1` WHERE `UID` = user_id。</p>
<p>在存储过程中输出 user_id 发现英文内容正常，但是中文内容乱码。</p>
<p>开始以为存储过程的编码有问题，但是不使用变量的内容又正常。上网查了一下，有人遇到同样的问题：</p>
<p><a href="http://www.google.com/url?sa=t&amp;ct=res&amp;cd=1&amp;url=http%3A%2F%2Fbugs.mysql.com%2Fbug.php%3Fid%3D28567&amp;ei=aNXhR-GwGJGq6wOtoaC0CA&amp;usg=AFQjCNEy654sRAlz-r0xRYGcMuR34i0W3Q&amp;sig2=LD5T7o5d_96SV3YpQJRROA">http://www.google.com/url?sa=t&amp;ct=res&amp;cd=1&amp;url=http%3A%2F%2Fbugs.mysql.com%2Fbug.php%3Fid%3D28567&amp;ei=aNXhR-GwGJGq6wOtoaC0CA&amp;usg=AFQjCNEy654sRAlz-r0xRYGcMuR34i0W3Q&amp;sig2=LD5T7o5d_96SV3YpQJRROA</a></p>
<p>但是显然，他的问题只要正确设置编码即可。</p>
<p>突然灵光一现，NND，character set 这个东西我忽略了。正解如下：</p>
<p>CREATE PROCEDURE `PROC_FOOBAR`(id INTEGER)<br />
BEGIN</p>
<p>DECLARE code, user_id VARCHAR(32) CHARACTER SET utf8;</p>
<p>&#8211; 省略代码若干</p>
<p>END</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2008/03/mysql-%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e4%b8%ad%ef%bc%8c%e4%b8%ad%e6%96%87%e5%8f%98%e9%87%8f%e5%87%ba%e7%8e%b0%e4%b9%b1%e7%a0%81%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在PHP中使用Lucene 讲义幻灯、代码示例</title>
		<link>http://www.mikespook.com/2007/08/%e5%9c%a8php%e4%b8%ad%e4%bd%bf%e7%94%a8lucene-%e8%ae%b2%e4%b9%89%e5%b9%bb%e7%81%af%e3%80%81%e4%bb%a3%e7%a0%81%e7%a4%ba%e4%be%8b/</link>
		<comments>http://www.mikespook.com/2007/08/%e5%9c%a8php%e4%b8%ad%e4%bd%bf%e7%94%a8lucene-%e8%ae%b2%e4%b9%89%e5%b9%bb%e7%81%af%e3%80%81%e4%bb%a3%e7%a0%81%e7%a4%ba%e4%be%8b/#comments</comments>
		<pubDate>Mon, 27 Aug 2007 04:47:30 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[lucene]]></category>

		<guid isPermaLink="false">http://blog.xxiyy.com/index.php/archives/48</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
下载 9月2日的讲义幻灯和代码示例。

在线演示：www.i-fang.com/php/lucene4php/search.php

内容如下：

<span class="readmore"><a href="http://www.mikespook.com/2007/08/%e5%9c%a8php%e4%b8%ad%e4%bd%bf%e7%94%a8lucene-%e8%ae%b2%e4%b9%89%e5%b9%bb%e7%81%af%e3%80%81%e4%bb%a3%e7%a0%81%e7%a4%ba%e4%be%8b/" title="在PHP中使用Lucene 讲义幻灯、代码示例">阅读全文——共459字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p><a href="http://blog.xxiyy.com/wp-content/uploads/2007/08/lucene4php.zip">下载 9月2日的讲义幻灯和代码示例。</a></p>
<p>在线演示：<a href="http://www.i-fang.com/php/lucene4php/search.php">www.i-fang.com/php/lucene4php/search.php</a></p>
<p>内容如下：</p>
<p>&nbsp;<span id="more-48"></span></p>
<p align="center" style="margin-top: 0.42cm; page-break-after: avoid;"><font face="宋体"><font size="4">在</font></font><font face="宋体"><font size="4">PHP</font></font><font face="宋体"><font size="4">中使用</font></font><font face="宋体"><font size="4">Lucene</font></font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">概述</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">信息检索</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">三种模型</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Boolean</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Probabilistic</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Vector</font></p>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">文本处理</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">噪声词表</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">相关词汇表</font></p>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">查询</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">排序</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">辞典</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">分类和聚类</font></p>
</li>
</ol>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Lucene</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">介绍</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Lucene </font><font face="宋体">起源与发展</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">起源</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">sourceforge.net</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">apache</font></p>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">其他版本的 			</font><font face="宋体">Lucene</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">CLucene</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">PyLucene</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Lucy</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Lucene.net</font></p>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">PHP </font><font face="宋体">可用的 			</font><font face="宋体">Lucene</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Zend 				Framework Lucene</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Pecl 				CLucene extension</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Java Bridge 				Lucene</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">XML-PRC or 				WebService call</font></p>
</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">实例</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">建立索引</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">关于索引</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">索引的作用</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">倒排索引</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">多文件索引</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">复合索引</font></p>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">建立</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">文档</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">字段</font></p>
</li>
</ol>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">搜索</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">分词</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">查询语言</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">排序</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">限制返回结果数目</font></p>
</li>
</ol>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">总结</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Zend_Search_Lucene 		</font><font face="宋体">的限制</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">中文</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">性能</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">跨平台</font></p>
</li>
</ol>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">更好的实现方式</font></p>
<ol>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">XML-RPC or 			WebServcec or HTTP call</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">Java Bridge</font></p>
</li>
<li>
<p style="margin-bottom: 0cm;"><font face="宋体">基于</font><font face="宋体">Lucy</font><font face="宋体">的</font><font face="宋体">PHP 			extension</font></p>
</li>
</ol>
</li>
</ol>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2007/08/%e5%9c%a8php%e4%b8%ad%e4%bd%bf%e7%94%a8lucene-%e8%ae%b2%e4%b9%89%e5%b9%bb%e7%81%af%e3%80%81%e4%bb%a3%e7%a0%81%e7%a4%ba%e4%be%8b/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>在 Oracle 中完成 PHP5 对象的持久【收藏】</title>
		<link>http://www.mikespook.com/2007/08/%e5%9c%a8-oracle-%e4%b8%ad%e5%ae%8c%e6%88%90-php5-%e5%af%b9%e8%b1%a1%e7%9a%84%e6%8c%81%e4%b9%85%e3%80%90%e6%94%b6%e8%97%8f%e3%80%91/</link>
		<comments>http://www.mikespook.com/2007/08/%e5%9c%a8-oracle-%e4%b8%ad%e5%ae%8c%e6%88%90-php5-%e5%af%b9%e8%b1%a1%e7%9a%84%e6%8c%81%e4%b9%85%e3%80%90%e6%94%b6%e8%97%8f%e3%80%91/#comments</comments>
		<pubDate>Mon, 20 Aug 2007 12:02:24 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://blog.xxiyy.com/index.php/archives/46</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
www.oracle.com/technology/global/cn/pub/articles/oracle_php_cookbook/mckay_objects.html

虽然是 05 年的了，但现在看还是不错的一篇文章。应该也可以用于 mysql。

]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p><a href="http://www.oracle.com/technology/global/cn/pub/articles/oracle_php_cookbook/mckay_objects.html" onclick="window.open(this.href,'','resizable=no,location=no,menubar=no,scrollbars=no,status=no,toolbar=no,fullscreen=no,dependent=no,status'); return false">www.oracle.com/technology/global/cn/pub/articles/oracle_php_cookbook/mckay_objects.html</a></p>
<p>虽然是 05 年的了，但现在看还是不错的一篇文章。应该也可以用于 mysql。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2007/08/%e5%9c%a8-oracle-%e4%b8%ad%e5%ae%8c%e6%88%90-php5-%e5%af%b9%e8%b1%a1%e7%9a%84%e6%8c%81%e4%b9%85%e3%80%90%e6%94%b6%e8%97%8f%e3%80%91/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Oracle 10g 全文检索的一些笔记</title>
		<link>http://www.mikespook.com/2007/08/oracle-10g-%e5%85%a8%e6%96%87%e6%a3%80%e7%b4%a2%e7%9a%84%e4%b8%80%e4%ba%9b%e7%ac%94%e8%ae%b0/</link>
		<comments>http://www.mikespook.com/2007/08/oracle-10g-%e5%85%a8%e6%96%87%e6%a3%80%e7%b4%a2%e7%9a%84%e4%b8%80%e4%ba%9b%e7%ac%94%e8%ae%b0/#comments</comments>
		<pubDate>Wed, 15 Aug 2007 02:15:48 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[ctxcat]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[search]]></category>

		<guid isPermaLink="false">http://blog.xxiyy.com/index.php/archives/43</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
Oracle 10g 的全文检索分为两个部分：

索引创建 &#8211; 使用过滤器（Filter）对不同格式的内容进行提取，通过词法分析器（Lexer）将文本分离为有效词列表，创建并设置噪声词表、相关词表。

查询处理 &#8211; 在标准 SELECT 语句中通过 CONTEXT 和 CTXCAT 使用全文索引搜索。

<span class="readmore"><a href="http://www.mikespook.com/2007/08/oracle-10g-%e5%85%a8%e6%96%87%e6%a3%80%e7%b4%a2%e7%9a%84%e4%b8%80%e4%ba%9b%e7%ac%94%e8%ae%b0/" title="Oracle 10g 全文检索的一些笔记">阅读全文——共1532字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>Oracle 10g 的全文检索分为两个部分：</p>
<p>索引创建 &#8211; 使用过滤器（Filter）对不同格式的内容进行提取，通过词法分析器（Lexer）将文本分离为有效词列表，创建并设置噪声词表、相关词表。</p>
<p>查询处理 &#8211; 在标准 SELECT 语句中通过 CONTEXT 和 CTXCAT 使用全文索引搜索。<span id="more-43"></span></p>
<p>1. 索引创建</p>
<p>a. 数据存储（Datastore）</p>
<p>默认的数据存储方式为 DIRECT_DATASTORE。如果数据源通过 URL 地址定位，则使用 URL_DATASTORE。当多个数据源使用同一个索引时，要创建数据存储连接，并指定 MULTI_COLUMN_DATASTORE。</p>
<p>BEGIN<br />
&nbsp;&nbsp;&nbsp; CTX_DDL.CREATE_PREFERENCE(&#8216;FOOBAR_DATASTORE&#8217;, &#8216;MULTI_COLUMN_DATASTORE&#8217;);<br />
&nbsp;&nbsp;&nbsp; CTX_DDL.SET_ATTRIBUTE(&#8216;FOOBAR_DATASTORE&#8217;, &#8216;columns&#8217;, &#8216;FOO, BAR&#8217;);<br />
END;</p>
<p>SET_ATTRIBUTE 指定列，指定表和索引的工作在创建索引时完成。</p>
<p>b. 过滤器（Filter）</p>
<p>c. 分段器（Sectioner）</p>
<p>d. 词法分析器（Lexer）</p>
<p>对于中文有两种可选的词法分析器。CHINESE_VGRAM_LEXER 提取的标识符更大，无效标识符多。CHINESE_LEXER 更可靠，更好一些。</p>
<p>BEGIN<br />
&nbsp;&nbsp;&nbsp; CTX_DDL.CREATE_PREFERENCE(&#8216;FOOBAR_LEXER&#8217;, &#8216;CHINESE_LEXER&#8217;);<br />
END;</p>
<p>e. 相关词表（Wordlist）</p>
<p>f. 非索引字表（Stoplist）</p>
<p>排除在索引外的字词。如&ldquo;的&rdquo;、&ldquo;了&rdquo;等。Oracle 提供默认的 DEFAULT_STOPLIST。可扩展默认的 DEFAULT_STOPLIST，并通过 ADD_STOPWORD 添加自定义的非索引字表。也可通过扩展 BASIC_STOPLIST 创建全新的非索引字表。BASIC_STOPLIST 创建后是空的非索引字表。</p>
<p>BEGIN<br />
&nbsp;&nbsp;&nbsp; CTX_DDL.CREATE_STOPLIST(&#8216;FOOBAR_STOPLIST&#8217;,&nbsp; &lsquo;DEFAULT_STOPLIST&rsquo;);<br />
&nbsp;&nbsp;&nbsp; CTX_DDL.ADD_STOPWORD(&#8216;FOOBAR_STOPLIST&#8217;, &#8216;在&#8217;);<br />
END;</p>
<p>g. 存储首选项（Storage Preference）</p>
<p>h. 索引类型</p>
<p>Oracle 提供四种类型的索引：CONTEXT、CTXCAT、CTXRULE、CTXXPATH。</p>
<p>CREATE INDEX FOOBAR_IDX ON FOOBAR(FOO)<br />
INDEXTYPE IS CTXSYS.CONTEXT<br />
PARAMETERS (<br />
&nbsp;&nbsp;&nbsp; &#8216;LEXER FOOBAR_LEXER<br />
&nbsp;&nbsp;&nbsp; WORDLIST FOOBAR_LEXER<br />
&nbsp;&nbsp;&nbsp; STOPLIST FOOBAR_STOPLIST<br />
&nbsp;&nbsp;&nbsp; DATASTORE CTXSYS.DEFAULT_DATASTORE<br />
&nbsp;&nbsp;&nbsp; SYNC (ON COMMIT)&#8217;<br />
)</p>
<p>调用默认的索引参数，应加 CTXSYS 前缀，如：CTXSYS.DEFAULT_STOPLIST。</p>
<p>2. 查询处理</p>
<p>SELECT score(1), FOO, BAR <br />
FROM FOOBAR<br />
WHERE CONTAINS(FOO, &#8216;河蟹&#8217;, 1) &gt; 0</p>
<p>多个关键词搜索：</p>
<p>SELECT score(1), ID, &quot;FOO&quot;<br />
FROM FOOBAR<br />
WHERE <br />
&nbsp;&nbsp;&nbsp; CONTAINS(&quot;FOO&quot;, &#8216;数据,插入,验证&#8217;, 1) &gt; 0</p>
<p>另外，当在多列上进行全文检索，在 SELECT 的 WHERE 中只能出现索引建立时指定的列。Oracle 会自动在所有 MULTI_COLUMN_DATASTORE 中指定的列中进行查询。但若指定的列为空，即便是其他列有匹配内容，也不会被查询到。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2007/08/oracle-10g-%e5%85%a8%e6%96%87%e6%a3%80%e7%b4%a2%e7%9a%84%e4%b8%80%e4%ba%9b%e7%ac%94%e8%ae%b0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

