php常见的五种设计模式

设计模式不仅代表着更快开发健壮软件的有用方法,而且还提供了以友好的术语封装大型理念的方法。例如,您可以说您正在编写一个提供松散耦合的消息传递系统,也可以说你正在编写名称为观察者 的模式。

工厂模式

最初在设计模式 一书中,许多设计模式都鼓励使用松散耦合。要理解这个概念,让我们最好谈一下许多开发人员从事大型系统的艰苦历程。在更改一个代码片段时,就会发生问题,系统其他部分 —— 您曾认为完全不相关的部分中也有可能出现级联破坏。

该问题在于紧密耦合 。系统某个部分中的函数和类严重依赖于系统的其他部分中函数和类的行为和结构。您需要一组模式,使这些类能够相互通信,但不希望将它们紧密绑定在一起,以避免出现联锁。

在大型系统中,许多代码依赖于少数几个关键类。需要更改这些类时,可能会出现困难。例如,假设您有一个从文件读取的 User 类。您希望将其更改为从数据库读取的其他类,但是,所有的代码都引用从文件读取的原始类。这时候,使用工厂模式会很方便。

工厂模式 是一种类,它具有为您创建对象的某些方法。您可以使用工厂类创建对象,而不直接使用 new。这样,如果您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的所有代码会自动更改。

清单 1 显示工厂类的一个示列。等式的服务器端包括两个部分:数据库和一组 PHP 页面,这些页面允许您添加反馈、请求反馈列表并获取与特定反馈相关的文章。

清单 1. Factory1.php
<?php
interface IUser
{
  function getName();
}

class User implements IUser
{
  public function __construct( $id ) { }

  public function getName()
  {
    return "Jack";
  }
}

class UserFactory
{
  public static function Create( $id )
  {
    return new User( $id );
  }
}

$uo = UserFactory::Create( 1 );
echo( $uo->getName()."\n" );
?>

IUser 接口定义用户对象应执行什么操作。IUser 的实现称为 UserUserFactory 工厂类则创建 IUser 对象。此关系可以用图 1 中的 UML 表示。

图 1. 工厂类及其相关 IUser 接口和用户类

工厂类及其相关 IUser 接口和用户类

如果您使用 php 解释器在命令行上运行此代码,将得到如下结果:

% php factory1.php 
Jack
%

测试代码会向工厂请求 User 对象,并输出 getName 方法的结果。

有一种工厂模式的变体使用工厂方法。类中的这些公共静态方法构造该类型的对象。如果创建此类型的对象非常重要,此方法非常有用。例如,假设您需要先创建对象,然后设置许多属性。此版本的工厂模式会将该进程封装在单个位置中,这样,不用复制复杂的初始化代码,也不必将复制好的代码在在代码库中到处粘贴。

清单 2 显示使用工厂方法的一个示例。

清单 2. Factory2.php
<?php
interface IUser
{
  function getName();
}

class User implements IUser
{
  public static function Load( $id ) 
  {
        return new User( $id );
  }

  public static function Create( ) 
  {
        return new User( null );
  }

  public function __construct( $id ) { }

  public function getName()
  {
    return "Jack";
  }
}

$uo = User::Load( 1 );
echo( $uo->getName()."\n" );
?>

这段代码要简单得多。它仅有一个接口 IUser 和一个实现此接口的 User 类。User 类有两个创建对象的静态方法。此关系可用图 2 中的 UML 表示。

图 2. IUser 接口和带有工厂方法的 user 类

IUser 接口和带有工厂方法的用户类

在命令行中运行脚本产生的结果与清单 1 的结果相同,如下所示:

% php factory2.php 
Jack
%

如上所述,有时此类模式在规模较小的环境中似乎有些大材小用。不过,最好还是学习这种扎实的编码形式,以便应用于任意规模的项目中。

单元素模式

某些应用程序资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。

单元素模式可以满足此要求。如果应用程序每次包含且仅包含一个对象,那么这个对象就是一个单元素(Singleton)。清单 3 中的代码显示了 PHP V5 中的一个数据库连接单元素。

清单 3. Singleton.php
<?php
require_once("DB.php");

class DatabaseConnection
{
  public static function get()
  {
    static $db = null;
    if ( $db == null )
      $db = new DatabaseConnection();
    return $db;
  }

  private $_handle = null;

  private function __construct()
  {
    $dsn = 'mysql://root:password@localhost/photos';
    $this->_handle =& DB::Connect( $dsn, array() );
  }

  public function handle()
  {
    return $this->_handle;
  }
}

print( "Handle = ".DatabaseConnection::get()->handle()."\n" );
print( "Handle = ".DatabaseConnection::get()->handle()."\n" );
?>

此代码显示名为 DatabaseConnection 的单个类。您不能创建自已的 DatabaseConnection,因为构造函数是专用的。但使用静态 get 方法,您可以获得且仅获得一个 DatabaseConnection 对象。此代码的 UML 如图 3 所示。

图 3. 数据库连接单元素

数据库连接单元素

在两次调用间,handle 方法返回的数据库句柄是相同的,这就是最好的证明。您可以在命令行中运行代码来观察这一点。

% php singleton.php 
Handle = Object id #3
Handle = Object id #3
%

返回的两个句柄是同一对象。如果您在整个应用程序中使用数据库连接单元素,那么就可以在任何地方重用同一句柄。

您可以使用全局变量存储数据库句柄,但是,该方法仅适用于较小的应用程序。在较大的应用程序中,应避免使用全局变量,并使用对象和方法访问资源。

观察者模式

观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。

一个简单示例是系统中的用户列表。清单 4 中的代码显示一个用户列表,添加用户时,它将发送出一条消息。添加用户时,通过发送消息的日志观察者可以观察此列表。

清单 4. Observer.php
<?php
interface IObserver
{
  function onChanged( $sender, $args );
}

interface IObservable
{
  function addObserver( $observer );
}

class UserList implements IObservable
{
  private $_observers = array();

  public function addCustomer( $name )
  {
    foreach( $this->_observers as $obs )
      $obs->onChanged( $this, $name );
  }

  public function addObserver( $observer )
  {
    $this->_observers []= $observer;
  }
}

class UserListLogger implements IObserver
{
  public function onChanged( $sender, $args )
  {
    echo( "'$args' added to user list\n" );
  }
}

$ul = new UserList();
$ul->addObserver( new UserListLogger() );
$ul->addCustomer( "Jack" );
?>

此代码定义四个元素:两个接口和两个类。IObservable 接口定义可以被观察的对象,UserList 实现该接口,以便将本身注册为可观察。IObserver 列表定义要通过怎样的方法才能成为观察者,UserListLogger 实现 IObserver 接口。图 4 的 UML 中展示了这些元素。

图 4. 可观察的用户列表和用户列表事件日志程序

可观察的用户列表和用户列表事件日志程序

如果在命令行中运行它,您将看到以下输出:

% php observer.php 
'Jack' added to user list
%

测试代码创建 UserList,并将 UserListLogger 观察者添加到其中。然后添加一个消费者,并将这一更改通知 UserListLogger

认识到 UserList 不知道日志程序将执行什么操作很关键。可能存在一个或多个执行其他操作的侦听程序。例如,您可能有一个向新用户发送消息的观察者,欢迎新用户使用该系统。这种方法的价值在于 UserList 忽略所有依赖它的对象,它主要关注在列表更改时维护用户列表并发送消息这一工作。

此模式不限于内存中的对象。它是在较大的应用程序中使用的数据库驱动的消息查询系统的基础。

命令链模式

命令链 模式以松散耦合主题为基础,发送消息、命令和请求,或通过一组处理程序发送任意内容。每个处理程序都会自行判断自己能否处理请求。如果可以,该请求被处理,进程停止。您可以为系统添加或移除处理程序,而不影响其他处理程序。清单 5 显示了此模式的一个示例。

清单 5. Chain.php
<?php
interface ICommand
{
  function onCommand( $name, $args );
}

class CommandChain
{
  private $_commands = array();

  public function addCommand( $cmd )
  {
    $this->_commands []= $cmd;
  }

  public function runCommand( $name, $args )
  {
    foreach( $this->_commands as $cmd )
    {
      if ( $cmd->onCommand( $name, $args ) )
        return;
    }
  }
}

class UserCommand implements ICommand
{
  public function onCommand( $name, $args )
  {
    if ( $name != 'addUser' ) return false;
    echo( "UserCommand handling 'addUser'\n" );
    return true;
  }
}

class MailCommand implements ICommand
{
  public function onCommand( $name, $args )
  {
    if ( $name != 'mail' ) return false;
    echo( "MailCommand handling 'mail'\n" );
    return true;
  }
}

$cc = new CommandChain();
$cc->addCommand( new UserCommand() );
$cc->addCommand( new MailCommand() );
$cc->runCommand( 'addUser', null );
$cc->runCommand( 'mail', null );
?>

此代码定义维护 ICommand 对象列表的 CommandChain 类。两个类都可以实现 ICommand 接口 —— 一个对邮件的请求作出响应,另一个对添加用户作出响应。 图 5 给出了 UML。

图 5. 命令链及其相关命令

命令链及其相关命令

如果您运行包含某些测试代码的脚本,则会得到以下输出:

% php chain.php 
UserCommand handling 'addUser'
MailCommand handling 'mail'
%

代码首先创建 CommandChain 对象,并为它添加两个命令对象的实例。然后运行两个命令以查看谁对这些命令作出了响应。如果命令的名称匹配 UserCommand 或 MailCommand,则代码失败,不发生任何操作。

为处理请求而创建可扩展的架构时,命令链模式很有价值,使用它可以解决许多问题。

策略模式

我们讲述的最后一个设计模式是策略 模式。在此模式中,算法是从复杂类提取的,因而可以方便地替换。例如,如果要更改搜索引擎中排列页的方法,则策略模式是一个不错的选择。思考一下搜索引擎的几个部分 —— 一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,您可将排列部分放入另一个类中,以便更改页排列的方式,而不影响搜索引擎的其余代码。

作为一个较简单的示例,清单 6 显示了一个用户列表类,它提供了一个根据一组即插即用的策略查找一组用户的方法。

清单 6. Strategy.php
<?php
interface IStrategy
{
  function filter( $record );
}

class FindAfterStrategy implements IStrategy
{
  private $_name;

  public function __construct( $name )
  {
    $this->_name = $name;
  }

  public function filter( $record )
  {
    return strcmp( $this->_name, $record ) <= 0;
  }
}

class RandomStrategy implements IStrategy
{
  public function filter( $record )
  {
    return rand( 0, 1 ) >= 0.5;
  }
}

class UserList
{
  private $_list = array();

  public function __construct( $names )
  {
    if ( $names != null )
    {
      foreach( $names as $name )
      {
        $this->_list []= $name;
      }
    }
  }

  public function add( $name )
  {
    $this->_list []= $name;
  }

  public function find( $filter )
  {
    $recs = array();
    foreach( $this->_list as $user )
    {
      if ( $filter->filter( $user ) )
        $recs []= $user;
    }
    return $recs;
  }
}

$ul = new UserList( array( "Andy", "Jack", "Lori", "Megan" ) );
$f1 = $ul->find( new FindAfterStrategy( "J" ) );
print_r( $f1 );

$f2 = $ul->find( new RandomStrategy() );
print_r( $f2 );
?>

此代码的 UML 如图 6 所示。

图 6. 用户列表和用于选择用户的策略

用户列表和用于选择用户的策略

UserList 类是打包名称数组的一个包装器。它实现 find 方法,该方法利用几个策略之一来选择这些名称的子集。这些策略由 IStrategy 接口定义,该接口有两个实现:一个随机选择用户,另一个根据指定名称选择其后的所有名称。运行测试代码时,将得到以下输出:

% php strategy.php 
Array
(
    [0] => Jack
    [1] => Lori
    [2] => Megan
)
Array
(
    [0] => Andy
    [1] => Megan
)
%

测试代码为两个策略运行同一用户列表,并显示结果。在第一种情况中,策略查找排列在 J 后的任何名称,所以您将得到 Jack、Lori 和 Megan。第二个策略随机选取名称,每次会产生不同的结果。在这种情况下,结果为 Andy 和 Megan。

策略模式非常适合复杂数据管理系统或数据处理系统,二者在数据筛选、搜索或处理的方式方面需要较高的灵活性。

结束语

本文介绍的仅仅是 PHP 应用程序中使用的几种最常见的设计模式。在设计模式 一书中演示了更多的设计模式。不要因架构的神秘性而放弃。模式是一种绝妙的理念,适用于任何编程语言、任何技能水平。

文章来源:http://www.ibm.com/developerworks/cn/opensource/os-php-designptrns/

解决网站大流量,高并发

大流量、高并发的网站的处理,最基本的是服务器性能的支持,其次是对sql语句的优化(尽量减少数据库连接),3、禁止外部盗链,4、控制大文件下载,5、使用不同主机分流,6、使用流量分析统计优化,

首先,确认服务器硬件是否足够支持当前的流量。

普通的P4服务器一般最多能支持每天10万独立IP,如果访问量比这个还要大,
那么必须首先配置一台更高性能的专用服务器才能解决问题

,否则怎么优化都不可能彻底解决性能问题。

其次,优化数据库访问。

前台实现完全的静态化当然最好,可以完全不用访问数据库,不过对于频繁更新的网站,
静态化往往不能满足某些功能。

缓存技术就是另一个解决方案,就是将动态数据存储到缓存文件中,动态网页直接调用
这些文件,而不必再访问数据库,WordPress和Z-Blog都大量使用这种缓存技术。

如果确实无法避免对数据库的访问,那么可以尝试优化数据库的查询SQL.避免使用
Select * from这样的语句,每次查询只返回自己需要的结果,避免短时间内的大
量SQL查询。

第三,禁止外部的盗链。

外部网站的图片或者文件盗链往往会带来大量的负载压力,因此应该严格限制外部对
于自身的图片或者文件盗链,好在目前可以简单地通过refer来控制盗链,Apache自
己就可以通过配置来禁止盗链,IIS也有一些第三方的ISAPI可以实现同样的功能。当
然,伪造refer也可以通过代码来实现盗链,不过目前蓄意伪造refer盗链的还不多,
可以先不去考虑,或者使用非技术手段来解决,比如在图片上增加水印。

第四,控制大文件的下载。

大文件的下载会占用很大的流量,并且对于非SCSI硬盘来说,大量文件下载会消耗
CPU,使得网站响应能力下降。因此,尽量不要提供超过2M的大文件下载,如果需要
提供,建议将大文件放在另外一台服务器上。

第五,使用不同主机分流主要流量

将文件放在不同的主机上,提供不同的镜像供用户下载。比如如果觉得RSS文件占用
流量大,那么使用FeedBurner或者FeedSky等服务将RSS输出放在其他主机上,这
样别人访问的流量压力就大多集中在FeedBurner的主机上,RSS就不占用太多资源了。

第六,使用流量分析统计软件。

在网站上安装一个流量分析统计软件,可以即时知道哪些地方耗费了大量流量,哪些页
面需要再进行优化,因此,解决流量问题还需要进行精确的统计分析才可以。我推荐使
用的流量分析统计软件是Google Analytics(Google分析)。

文章来源:http://www.alixixi.com/program/a/2011070572214.shtml

OO思想

OO思想既面向对象的思想,OOA,面向对象的分析;OOD,面向对象的设计;OOP,面向对象的编程

OOA

Object-Oriented Analysis:面向对象分析方法

是在一个系统的开发过程中进行了系统业务调查以后,按照面向对象的思想来分析问题。OOA与结构化分析有较大的区别。OOA所强调的是在系统调查资料的基础上,针对OO方法所需要的素材进行的归类分析和整理,而不是对管理业务现状和方法的分析。

OOA(面向对象的分析)模型由5个层次(主题层、对象类层、结构层、属性层和服务层)和5个活动(标识对象类、标识结构、定义主题、定义属性和定义服务)组成。在这种方法中定义了两种对象类之间的结构,一种称为分类结构,一种称为组装结构。分类结构就是所谓的一般与特殊的关系。组装结构则反映了对象之间的整体与部分的关系。

OOA在定义属性的同时,要识别实例连接。实例连接是一个实例与另一个实例的映射关系。

OOA在定义服务的同时要识别消息连接。当一个对象需要向另一对象发送消息时,它们之间就存在消息连接。

OOA 中的5个层次和5个活动继续贯穿在OOD(画向对象的设计)过程中。OOD模型由4个部分组成。它们分别是设计问题域部分、设计人机交互部分、设计任务管理部分和设计数据管理部分。

一、OOA的主要原则。

(1)抽象:从许多事物中舍弃个别的、非本质的特征,抽取共同的、本质性的特征,就叫作抽象。抽象是形成概念的必须手段。

抽象原则有两方面的意义:第一,尽管问题域中的事物是很复杂的,但是分析员并不需要了解和描述它们的一切,只需要分析研究其中与系统目标有关的事物及其本质性特征。第二,通过舍弃个体事物在细节上的差异,抽取其共同特征而得到一批事物的抽象概念。

抽象是面向对象方法中使用最为广泛的原则。抽象原则包括过程抽象和数据抽象两个方面。

过程抽象是指,任何一个完成确定功能的操作序列,其使用者都可以把它看作一个单一的实体,尽管实际上它可能是由一系列更低级的操作完成的。

数据抽象是根据施加于数据之上的操作来定义数据类型,并限定数据的值只能由这些操作来修改和观察。数据抽象是OOA的核心原则。它强调把数据(属性)和操作(服务)结合为一个不可分的系统单位(即对象),对象的外部只需要知道它做什么,而不必知道它如何做。

(2)封装就是把对象的属性和服务结合为一个不可分的系统单位,并尽可能隐蔽对象的内部细节。

(3)继承:特殊类的对象拥有的其一般类的全部属性与服务,称作特殊类对一般类的继承。

在OOA中运用继承原则,就是在每个由一般类和特殊类形成的一般—特殊结构中,把一般类的对象实例和所有特殊类的对象实例都共同具有的属性和服务,一次性地在一般类中进行显式的定义。在特殊类中不再重复地定义一般类中已定义的东西,但是在语义上,特殊类却自动地、隐含地拥有它的一般类(以及所有更上层的一般类)中定义的全部属性和服务。继承原则的好处是:使系统模型比较简练也比较清晰。

(4)分类:就是把具有相同属性和服务的对象划分为一类,用类作为这些对象的抽象描述。分类原则实际上是抽象原则运用于对象描述时的一种表现形式。

(5)聚合:又称组装,其原则是:把一个复杂的事物看成若干比较简单的事物的组装体,从而简化对复杂事物的描述。

(6)关联:是人类思考问题时经常运用的思想方法:通过一个事物联想到另外的事物。能使人发生联想的原因是事物之间确实存在着某些联系。

(7)消息通信:这一原则要求对象之间只能通过消息进行通信,而不允许在对象之外直接地存取对象内部的属性。通过消息进行通信是由于封装原则而引起的。在OOA中要求用消息连接表示出对象之间的动态联系。

(8)粒度控制:一般来讲,人在面对一个复杂的问题域时,不可能在同一时刻既能纵观全局,又能洞察秋毫。因此需要控制自己的视野:考虑全局时,注意其大的组成部分,暂时不详察每一部分的具体的细节;考虑某部分的细节时则暂时撇开其余的部分。这就是粒度控制原则。

(9)行为分析:现实世界中事物的行为是复杂的。由大量的事物所构成的问题域中各种行为往往相互依赖、相互交织。

二、面向对象分析产生三种分析模型

1、对象模型:对用例模型进行分析,把系统分解成互相协作的分析类,通过类图/对象图描述对象/对象的属性/对象间的关系,是系统的静态模型

2、动态模型:描述系统的动态行为,通过时序图/协作图描述对象的交互,以揭示对象间如何协作来完成每个具体的用例,单个对象的状态变化/动态行为可以通过状态图来表达

3、功能模型(即用例模型à作为输入)。

三、OOA的主要优点

(1)加强了对问题域和系统责任的理解;

(2)改进与分析有关的各类人员之间的交流;

(3)对需求的变化具有较强的适应性;

(4)支持软件复用。

(5)贯穿软件生命周期全过程的一致性。

(6)实用性;

(7)有利于用户参与。

四、OOA方法的基本步骤

在用OOA具体地分析一个事物时,大致上遵循如下五个基本步骤:

第一步,确定对象和类。这里所说的对象是对数据及其处理方式的抽象,它反映了系统保存和处理现实世界中某些事物的信息的能力。类是多个对象的共同属性和方法集合的描述,它包括如何在一个类中建立一个新对象的描述。

第二步,确定结构(structure)。结构是指问题域的复杂性和连接关系。类成员结构反映了泛化-特化关系,整体-部分结构反映整体和局部之间的关系。

第三步,确定主题(subject)。主题是指事物的总体概貌和总体分析模型。

第四步,确定属性(attribute)。属性就是数据元素,可用来描述对象或分类结构的实例,可在图中给出,并在对象的存储中指定。

第五步,确定方法(method)。方法是在收到消息后必须进行的一些处理方法:方法要在图中定义,并在对象的存储中指定。对于每个对象和结构来说,那些用来增加、修改、删除和选择一个方法本身都是隐含的(虽然它们是要在对象的存储中定义的,但并不在图上给出),而有些则是显示的。

OOD

面向对象设计(Object-Oriented Design,OOD)方法是OO方法中一个中间过渡环节。其主要作用是对OOA分析的结果作进一步的规范化整理,以便能够被OOP直接接受。

面向对象设计(OOD)是一种软件设计方法,是一种工程化规范。这是毫无疑问的。按照Bjarne Stroustrup的说法,面向对象的编程范式(paradigm)是[Stroustrup, 97]:

l 决定你要的类;

l 给每个类提供完整的一组操作;

l 明确地使用继承来表现共同点。

由这个定义,我们可以看出:OOD就是“根据需求决定所需的类、类的操作以及类之间关联的过程”。

OOD的目标是管理程序内部各部分的相互依赖。为了达到这个目标,OOD要求将程序分成块,每个块的规模应该小到可以管理的程度,然后分别将各个块隐藏在接口(interface)的后面,让它们只通过接口相互交流。比如说,如果用OOD的方法来设计一个服务器-客户端(client-server)应用,那么服务器和客户端之间不应该有直接的依赖,而是应该让服务器的接口和客户端的接口相互依赖。

这种依赖关系的转换使得系统的各部分具有了可复用性。还是拿上面那个例子来说,客户端就不必依赖于特定的服务器,所以就可以复用到其他的环境下。如果要复用某一个程序块,只要实现必须的接口就行了。

OOD是一种解决软件问题的设计范式(paradigm),一种抽象的范式。使用OOD这种设计范式,我们可以用对象(object)来表现问题领域(problem domain)的实体,每个对象都有相应的状态和行为。我们刚才说到:OOD是一种抽象的范式。抽象可以分成很多层次,从非常概括的到非常特殊的都有,而对象可能处于任何一个抽象层次上。另外,彼此不同但又互有关联的对象可以共同构成抽象:只要这些对象之间有相似性,就可以把它们当成同一类的对象来处理。

一、OOD背景知识

计算机硬件技术却在飞速发展。从几十年前神秘的庞然大物,到现在随身携带的移动芯片;从每秒数千次运算到每秒上百亿次运算。当软件开发者们还在寻找能让软件开发生产力提高一个数量级的“银弹”[Brooks, 95]时,硬件开发的生产力早已提升了百倍千倍。

硬件工程师们能够如此高效,是因为他们都很懒惰。他们永远恪守“不要去重新发明轮子”的古训。Grady Booch把这些黑箱称为类属(class category),现在我们则通常把它们称为“组件(component)”。

类属是由被称为类(class)的实体组成的,类与类之间通过关联(relationship)结合在一起。一个类可以把大量的细节隐藏起来,只露出一个简单的接口,这正好符合人们喜欢抽象的心理。所以,这是一个非常伟大的概念,因为它给我们提供了封装和复用的基础,让我们可以从问题的角度来看问题,而不是从机器的角度来看问题。

软件的复用最初是从函数库和类库开始的,这两种复用形式实际上都是白箱复用。到90年代,开始有人开发并出售真正的黑箱软件模块:框架(framework)和控件(control)。框架和控件往往还受平台和语言的限制,现在软件技术的新潮流是用SOAP作为传输介质的Web Service,它可以使软件模块脱离平台和语言的束缚,实现更高程度的复用。但是想一想,其实Web Service也是面向对象,只不过是把类与类之间的关联用XML来描述而已[Li, 02]。

在过去的十多年里,面向对象技术对软件行业起到了极大的推动作用。在可以预测的将来,它仍将是软件设计的主要技术——至少我看不到有什么技术可以取代它的。

二、OOD到底从哪儿来?

有很多人都认为:OOD是对结构化设计(Structured Design,SD)的扩展,其实这是不对的。OOD的软件设计观念和SD完全不同。SD注重的是数据结构和处理数据结构的过程。而在OOD中,过程和数据结构都被对象隐藏起来,两者几乎是互不相关的。不过,追根溯源,OOD和SD有着非常深的渊源。

1967年前后,OOD和SD 的概念几乎同时诞生,它们分别以不同的方式来表现数据结构和算法。当时,围绕着这两个概念,很多科学家写了大量的论文。其中,由Dijkstra和 Hoare两人所写的一些论文讲到了“恰当的程序控制结构”这个话题,声称goto语句是有害的,应该用顺序、循环、分支这三种控制结构来构成整个程序流程。这些概念发展构成了结构化程序设计方法;而由Ole-Johan Dahl所写的另一些论文则主要讨论编程语言中的单位划分,其中的一种程序单位就是类,它已经拥有了面向对象程序设计的主要特征。

这两种概念立刻就分道扬镳了。在结构化这边的历史大家都很熟悉:NATO会议采纳了Dijkstra的思想,整个软件产业都同意goto语句的确是有害的,结构化方法、瀑布模型从70年代开始大行其道。同时,无数的科学家和软件工程师也帮助结构化方法不断发展完善,其中有很多今天足以使我们振聋发聩的名字,例如Constantine、Yourdon、DeMarco和Dijkstra。有很长一段时间,整个世界都相信:结构化方法就是拯救软件工业的 “银弹”。当然,时间最后证明了一切。

而此时,面向对象则在研究和教育领域缓慢发展。结构化程序设计几乎可以应用于任何编程语言之上,而面向对象程序设计则需要语言的支持[1],这也妨碍了面向对象技术的发展。实际上,在60年代后期,支持面向对象特性的语言只有Simula-67这一种。到70年代,施乐帕洛阿尔托研究中心(PARC)的 Alan Key等人又发明了另一种基于面向对象方法的语言,那就是大名鼎鼎的Smalltalk。但是,直到80年代中期,Smalltalk和另外几种面向对象语言仍然只停留在实验室里。

到90年代,OOD突然就风靡了整个软件行业,这绝对是软件开发史上的一次革命。不过,登高才能望远,新事物总是站在旧事物的基础之上的。70年代和80年代的设计方法揭示出许多有价值的概念,谁都不能也不敢忽视它们,OOD也一样。

三、OOD和传统方法有什么区别?

还记得结构化设计方法吗?程序被划分成许多个模块,这些模块被组织成一个树型结构。这棵树的根就是主模块,叶子就是工具模块和最低级的功能模块。同时,这棵树也表示调用结构:每个模块都调用自己的直接下级模块,并被自己的直接上级模块调用。

那么,哪个模块负责收集应用程序最重要的那些策略?当然是最顶端的那些。在底下的那些模块只管实现最小的细节,最顶端的模块关心规模最大的问题。所以,在这个体系结构中越靠上,概念的抽象层次就越高,也越接近问题领域;体系结构中位置越低,概念就越接近细节,与问题领域的关系就越少,而与解决方案领域的关系就越多。

但是,由于上方的模块需要调用下方的模块,所以这些上方的模块就依赖于下方的细节。换句话说,与问题领域相关的抽象要依赖于与问题领域无关的细节!这也就是说,当实现细节发生变化时,抽象也会受到影响。而且,如果我们想复用某一个抽象的话,就必须把它依赖的细节都一起拖过去。

而在OOD中,我们希望倒转这种依赖关系:我们创建的抽象不依赖于任何细节,而细节则高度依赖于上面的抽象。这种依赖关系的倒转正是OOD和传统技术之间根本的差异,也正是OOD思想的精华所在。

四、OOD步骤

细化重组类

细化和实现类间关系,明确其可见性

增加属性,指定属性的类型与可见性

分配职责,定义执行每个职责的方法

对消息驱动的系统,明确消息传递方式

利用设计模式进行局部设计

画出详细的类图与时序图

五、OOD设计过程中要展开的主要几项工作

(一)对象定义规格的求精过程

对于OOA所抽象出来的对象-&-类以及汇集的分析文档,OOD需要有一个根据设计要求整理和求精的过程,使之更能符合OOP的需要。这个整理和求精过程主要有两个方面:一是要根据面向对象的概念

模型整理分析所确定的对象结构、属性、方法等内容,改正错误的内容,删去不必要和重复的内容等。二是进行分类整理,以便于下一步数据库设计和程序处理模块设计的需要。整理的方法主要是进行归

类,对类一&一对象、属性、方法和结构、主题进行归类。

(二)数据模型和数据库设计

数据模型的设计需要确定类-&-对象属性的内容、消息连接的方式、系统访问、数据模型的方法等。最后每个对象实例的数据都必须落实到面向对象的库结构模型中。

(三)优化

OOD的优化设计过程是从另一个角度对分析结果和处理业务过程的整理归纳,优化包括对象和结构的优化、抽象、集成。

对象和结构的模块化表示OOD提供了一种范式,这种范式支持对类和结构的模块化。这种模块符合一般模块化所要求的所有特点,如信息隐蔽性好,内部聚合度强和模块之间耦合度弱等。

集成化使得单个构件有机地结合在一起,相互支持。

六、OO方法的特点和面临的问题

OO方法以对象为基础,利用特定的软件工具直接完成从对象客体的描述到软件结构之间的转换。这是OO方法最主要的特点和成就。OO方法的应用解决了传统结构化开发方法中客观世界描述工具与软

件结构的不一致性问题,缩短了开发周期,解决了从分析和设计到软件模块结构之间多次转换映射的繁杂过程,是一种很有发展前途的系统开发方法。

但是同原型方法一样,OO方法需要一定的软件基础支持才可以应用,另外在大型的MIS开发中如果不经自顶向下的整体划分,而是一开始就自底向上的采用OO 方法开发系统,同样也会造成系统结构不合理、各部分关系失调等问题。所以OO方法和结构化方法目前仍是两种在系统开发领域相互依存的、不可替代的方法。

七、OOD能给我带来什么?

问这个问题的人,脑子里通常是在想“OOD能解决所有的设计问题吗?”没有银弹。OOD也不是解决一切设计问题、避免软件危机、捍卫世界和平……的银弹。OOD只是一种技术。但是,它是一种优秀的技术,它可以很好地解决目前的大多数软件设计问题——当然,这要求设计者有足够的能力。

OOD可能会让你头疼,因为要学会它、掌握它是很困难的;OOD甚至会让你失望,因为它也并不成熟、并不完美。OOD也会给你带来欣喜,它让你可以专注于设计,而不必操心那些细枝末节;OOD也会使你成为一个更好的设计师,它能提供给你很好的工具,让你能开发出更坚固、更可维护、更可复用的软件。

OOP

面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP 达到了软件工程的三个主要目标:重用性、灵活性和扩展性。为了实现整体运算,每个对象都能够接收信息、处理数据和向其它对象发送信息。OOP 主要有以下的概念和组件:

组件 - 数据和功能一起在运行着的计算机程序中形成的单元,组件在 OOP 计算机程序中是模块和结构化的基础。

抽象性 - 程序有能力忽略正在处理中信息的某些方面,即对信息主要方面关注的能力。

封装 - 也叫做信息封装:确保组件不会以不可预期的方式改变其它组件的内部状态;只有在那些提供了内部状态改变方法的组件中,才可以访问其内部状态。每类组件都提供了一个与其它组件联系的接口,并规定了其它组件进行调用的方法。

多态性 - 组件的引用和类集会涉及到其它许多不同类型的组件,而且引用组件所产生的结果得依据实际调用的类型。

继承性 - 允许在现存的组件基础上创建子类组件,这统一并增强了多态性和封装性。典型地来说就是用类来对组件进行分组,而且还可以定义新类为现存的类的扩展,这样就可以将类组织成树形或网状结构,这体现了动作的通用性。

由于抽象性、封装性、重用性以及便于使用等方面的原因,以组件为基础的编程在脚本语言中已经变得特别流行。Python 和 Ruby 是最近才出现的语言,在开发时完全采用了 OOP 的思想,而流行的 Perl 脚本语言从版本5开始也慢慢地加入了新的面向对象的功能组件。用组件代替“现实”上的实体成为 JavaScript(ECMAScript) 得以流行的原因,有论证表明对组件进行适当的组合就可以在英特网上代替 HTML 和 XML 的文档对象模型(DOM)。

设计模式、技术和直觉构成严峻的挑战。这是选择编程语言之前必须认识到的,尽管不同语言的设计特性可能促进或者阻碍这一转化。

在网络应用的增长中,一个很重要的部分是小型移动设备和特殊Internet设备的爆炸性增长。这些设备各有各的操作系统,或者只在某种特定的设备领域内有共同的操作系统。我们现在还可以一一列举出这些设备——家庭接入设备、蜂窝电话、电子报纸、PDA、自动网络设备等等。但是这些设备领域的数量和深入程度将会很快变得难以估量。我们都知道这个市场大得惊人,PC的兴起与之相比不过小菜一碟。因此在这些设备的应用程序市场上,竞争将会相当残酷。获胜的重要手段之一,就是尽快进入市场。开发人员需要优秀的工具,迅速高效地撰写和调试他们的软件。平台无关性也是制胜秘诀之一,它使得程序员能够开发出支持多种设备平台的软件。

我预期的另一个变化是,我们对于代码(Java)和数据(XML)协同型应用程序的开发能力将会不断提高。这种协同是开发强大应用程序的核心目标之一。我们从XML的迅速流行和ebXML规范的进展中,已经看到了这个趋势。ebXML是一个针对电子商务和国际贸易的,基于XML的开放式基础构架,由联合国贸易促进和电子商务中心(UN/CEFACT)与结构性信息标准推进组织(OASIS)共同开发。

我们能否期望出现一个真正的面向组件(component-oriented)的语言?它的创造者会是谁呢?

Stroustrup: 我怀疑,这个领域中之所以缺乏成果,正是因为人们——主要是那些非程序员们——对“组件”这个意义含糊的字眼寄予了太多的期望。这些人士梦想,有朝一日,组件会以某种方式把程序员赶出历史舞台。以后那些称职的“设计员”只需利用预先调整好的组件,把鼠标拖一拖放一放,就把系统组合出来。对于软件工具厂商来说,这种想法还有另一层意义,他们认为,到时候只有他们才保留有必要的技术,有能力编写这样的组件。

这种想法有一个最基本的谬误:这种组件很难获得广泛欢迎。一个单独的组件或框架(framework),如果能够满足一个应用程序或者一个产业领域对所提出的大部分要求的话,对于其制造者来说就是划算的产品,而且技术上也不是很困难。可是该产业内的几个竞争者很快就会发现,如果所有人都采用这些组件,那么彼此之间的产品就会变得天下大同,没什么区别,他们将沦为简单的办事员,主要利润都将钻进那些组件/框架供应商的腰包里!

小“组件”很有用,不过产生不了预期的杠杆效应。中型的、更通用的组件非常有用,但是构造时需要非同寻常的弹性。

在C++中,我们综合运用不同共享形式的类体系(class hierarchies),以及使用templates精心打造的接口,在这方面取得了一定的进展。我期待在这个领域取得一些有趣和有用的成果,不过我认为这种成果很可能是一种新的C++程序设计风格,而不是一种新的语言。

Lindholm: 编写面向组件的应用程序,好像更多的是个投资、设计和程序员管理方面的问题,而不是一个编程语言问题。当然某些语言在这方面具有先天优势,不过如果说有什么魔术般的新语言能够大大简化组件的编写难度,那纯粹是一种误导。

微软已经将全部赌注押在C#上,其他语言何去何从?

Stroustrup: C++在下一个十年里仍然将是一种主流语言。面对新的挑战,它会奋起应对。一个创造了那么多出色系统的语言,绝不会“坐视落花流水春去也”。

我希望微软认识到,它在C++(我指的是ISO标准C++)上有着巨大的利益,C++是它与IT世界内其他人之间的一座桥梁,是构造大型系统和嵌入式系统的有效工具,也是满足高性能需求的利器。其他语言,似乎更注重那些四平八稳的商用程序。

竞争

C#会不会获得广泛的接受,并且挤掉其他的语言?

Lindholm: 通常,一种语言既不会从别的语言那里获利,也不会被挤掉。那些坚定的Fortran程序员不还用着Fortran吗?对于个人来说,语言的选择当然因时而异,但就整体而言,语言的种类只会递增,也就是说,它们之间的关系是“有你有我”而不是“有你没我”。

对于一个新语言的接受程度,往往取决于其能力所及。Java技术被迅速接受,原因是多方面的,Internet和World Wide Web接口,在其他技术面前的挫折感,对于Java技术发展方向的全面影响能力,都是原因。另一个重要的原因是Java独立于厂商,这意味着在兼容产品面前可以从容选择。

C#是否会获得广泛接受?视情况而定。总的来说,那些对于平台无关性和厂商无关性漠不关心的程序员,可能会喜欢C#。那些跟微软平台捆在一起人当然可能想要寻找VB 和VC的一个出色的替代品。但是对于程序跨平台执行能力特别关注的程序员,将会坚守Java之类的语言。这种能力对于多重访问设备(multiple access devices)和分布式计算模型至关重要,而Java语言提供了一个标准的、独立于厂商运行时环境。

Stroustrup:C#的流行程度几乎完全取决于微软投入的资金多少。看上去C#的兴起肯定会牺牲掉其他一些语言的利益,但是事实上未必如此。Java的蓬勃发展并没有给C++带来衰败。C++的应用仍然在稳定增长(当然,已经不是爆炸性的增长了)。也许其他的语言也还能获得自己的一席之地。

不过,我实在看不出有什么必要再发明一种新的专有语言。特别是微软,既生VB,何需C#?

六、发展 vs. 革新

(Evolution vs. Revolution)

C++是一种发展型的语言,Java和C#似乎更像是革新型语言(它们是从头设计的)?什么时候,革新型的语言才是必需的呢?

Lindholm: Java技术并非凭空出世,反而更像是发展型的。Java所有的特性,在Java平台推出之前,都至少已经存在于另一种环境之中。Java的贡献在于,在众多的特性和权衡中,做出了合理的选择,使得产品既实用,又优雅。Java技术对于程序员的态度是:抚养,但不溺爱。

Stroustrup:从技术上讲,我并不认为Java和C#是什么“从头设计的”革新型语言。倘若Java是从技术原则出发,从头设计,大概就不会模仿C/C++那种丑陋和病态的语法了(不必惊讶,Stroustrup在很多场合表示过,C++采用C的语法形式,实在是迫于兼容性。他本人更偏爱Simula的语法——译者)。

我认为,只有当程序员们面对的问题发生了根本的变化的时候,或者当我们发现了全新的、极其优越的程序设计技术,又完全不能为现存语言所支持的时候,我们才需要全新的语言。问题是,我们恐怕永远也碰不到那些“根本”、“全新”的情况。

我以为,自从OOP问世以来,可称为“根本”的新型程序设计技术,唯有泛型程序设计(generic programming)和生成式程序设计(generative programming)技术,这两项技术主要是源于C++ templates技术的运用,也有一部分曾经被视为面向对象和函数式语言(functional languages)的次要成分,现在都变成正式、可用和可承受的技术了。我对于目前C++模板(template)程序设计的成果非常兴奋。例如,像POOMA, Blitz++和MTL等程序库,在很多地方改变了数值计算的方式。

C#的一个“卖点”,就是它们的简单性。现在Java是不是快失去这个卖点了?

Stroustrup:新语言总是宣称自己如何如何简单,对老语言的复杂性颇多非议。其实这种所谓的“简单性”,简单地说,就是不成熟性。语言的复杂性,是在解决现实世界中极为烦琐和特殊的复杂问题的过程中逐渐增加的。一个语言只要活的时间够长,总会有某些地方逐渐复杂起来,或者是语言本身,或者是程序库和工具。C++和Java显然都不例外,我看C#也一样。如果一种语言能够度过自己的幼年时代,它会发现,自己无论是体积还是复杂性都大大增加了。

Lindholm:Java技术的的功能在增加,需要学习的东西也在增加。不过功能的增加并不一定带来复杂性的增加。Java技术的发展,并没有使学习曲线更加陡峭,只是让它继续向右方延展了。

标准

标准化语言和开放型语言各自的优点和缺点何在?

Lindholm:对于一个开放、不允许专有扩展、具有权威的强制性标准语言或者运行环境来说,不存在什么缺点。允许专有扩展就意味着允许厂商下套子绑架客户。特别重要的是,必须让整个平台,而不只是其中一部分完全标准化,才能杜绝厂商们利用高层次的专有API下套子。客户要求有选择厂商的自由,他们既要有创造性,又需要兼容性。

Stroustrup:对于一个语言,如C/C++来说,建立正式标准(如ISO标准)最大的好处,在于可以防止某一个厂商操纵这种语言,把它当成自己的摇钱树。多个厂商的竞争给用户带来的是较低的价位和较好的稳定性。

专有语言的好处,一是流行,二是便宜(不过等你被套牢了之后,情况就会起变化),三是对于商业性需求可以做出快速的反应。

标准化语言的特点之一是,它不能忽略特殊用户的需求。比如我在AT&T中所考虑的东西,其规模、可靠性和效率要求,跟那些普通厂商关注的大众软件相比,根本不可同日而语。那些公司很自然只关注主要的需求。

然而,多数大机构和身处前沿的公司,都有着特殊的需求。C++的设计是开放、灵活和高效的,能够满足我所能想象的任何需求。跟其他的现代语言相比,C++的家长式作风可谓少之又少,原因就在这。当然,不能赞赏这一点的人会诟病C++的“危险”。

拥有正式和开放标准的语言主要是为编程工具的使用者和客户服务的,而拥有专属“标准”的语言,主要是为厂商服务的。

文章来源:http://blog.163.com/whc1985@126/blog/static/5265959620100892220498/

linux下php扩展zip,ftp等安装

linux下编译安装的php第一次安装时没有开启zip扩展,按这个方式可开启扩展,其他扩展的开启方法可参考

一、ZIP扩展安装

1、进入安装原php的源码目录,我的目录是在:
cd /home/test/software/php-5.2.8

2、进入zip扩展目录
cd ext/zip/

3、开始编译安装
/usr/local/webserver/php/bin/phpize
./configure –with-php-config=/usr/local/webserver/php/bin/php-config
make
make install

这样就会在/home/test/software/php-5.2.8/ext/zip/modules/下生成zip.so的文件。

4、修改php.ini文件
vi /usr/local/webserver/php/etc/php.ini

添加extension = “zip.so”

5、使其修改生效
/usr/local/webserver/php/sbin/php-fpm reload

php 实现 输出给定字符组的任意排列

php 实现 输出给定字符组的全部任意排列

function output($temp,$level)
{
for($i=0;$i<$level;$i++)
{
echo $temp[$i];
}
echo ‘<br>’;

}

function quanpai($arr,$flag,$level,$num,$temp)
{

if($level>=$num) {
output($temp,$num);
}
for($i=0;$i<$num;$i++){
if($flag[$i] == 0){
$temp[$level] = $arr[$i];
$flag[$i]=1;
quanpai($arr,$flag,$level+1,$num,$temp);
$flag[$i]=0;
}
}
}

$arr=array(a,b,c);
$len=count($arr);
$i=0;
$flag=array();
$temp=array();
while($i<$len){$flag[$i]=0;$i++;}

quanpai($arr,$flag,0,$len,$temp);

由浅入深探究mysql索引结构原理、性能分析与优化

摘要:

第一部分:基础知识

第二部分:MYISAM和INNODB索引结构

1、 简单介绍B-tree B+ tree树

2、 MyisAM索引结构

3、 Annode索引结构

4、 MyisAM索引与InnoDB索引相比较

第三部分:MYSQL优化

1、表数据类型选择

2、sql语句优化

(1)     最左前缀原则

(1.1)  能正确的利用索引

(1.2)  不能正确的利用索引

(1.3)  如果一个查询where子句中确实不需要password列,那就用“补洞”。

(1.4)  like

(2)     Order by 优化

(2.1) filesort优化算法.

(2.2) 单独order by 用不了索引,索引考虑加where 或加limit

(2.3) where + orerby 类型,where满足最左前缀原则,且orderby的列和where子句用到的索引的列的子集。即是(a,b,c)索引,where满足最左前缀原则且order by中列a、b、c的任意组合

(2.4) where + orerby+limit

(2.5) 如何考虑order by来建索引

(3)     隔离列

(4)     OR、IN、UNION ALL,可以尝试用UNION ALL

(4.1) or会遍历表就算有索引

(4.2)关于in

(4.2) UNION All

(5)     范索引选择性

(6)     重复或多余索引

3、系统配置与维护优化

(1)     重要的一些变量

(2)     Fds optimize、Analyze、check、repair维护操作

(3)     表结构的更新与维护

第四部分:图说mysql查询执行流程

 

 

 

第一部分:基础知识:

索引

官方介绍索引是帮助MySQL高效获取数据的数据结构。笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里,不用一页一页查阅找出需要的资料。关键字index

————————————————————-

唯一索引

强调唯一,就是索引值必须唯一,关键字unique index

创建索引:

1、create unique index 索引名 on 表名(列名);

2、alter table 表名 add unique index 索引名 (列名);

删除索引:

1、  drop index 索引名 on 表名;

2、  alter table 表名 drop index 索引名;

————————————————————-

主键

主键就是唯一索引的一种,主键要求建表时指定,一般用auto_increatment列,关键字是primary key

主键创建:

creat table test2 (id int not null primary key auto_increment);

————————————————————-

全文索引

InnoDB不支持,Myisam支持性能比较好,一般在 CHAR、VARCHAR 或 TEXT 列上创建。

Create table 表名( id int not null primary anto_increment,title

varchar(100),FULLTEXT(title))type=myisam

——————————

单列索引与多列索引

索引可以是单列索引也可以是多列索引(也叫复合索引)。按照上面形式创建出来的索引是单列索引,现在先看看创建多列索引:

create table test3 (id int not null primary key auto_increment,uname char

(8) not null default ”,password char(12) not null,INDEX(uname,password))type

=myisam;

注意:INDEX(a, b, c)可以当做a或(a, b)的索引来使用,但和b、c或(b,c)的索引来使用这是一个最左前缀的优化方法,在后面会有详细的介绍,你只要知道有这样两个概念

————————————————————-

聚集索引

一种索引,该索引中键值的逻辑顺序决定了表中相应行的物理顺序。 聚集索引确定表中数据的物理顺序。Mysql中myisam表是没有聚集索引的,innodb有(主键就是聚集索引),聚集索引在下面介绍innodb结构的时有详细介绍。

————————————————————-

查看表的索引

通过命令:Show index from 表名

如:

  1. mysql> show index from test3;
  2. +——-+————+———-+————–+————-+———–+————-+———-+——–+—-+
  3. | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part |
  4. Packed | Null | Index_type | Comment |
  5. +——-+————+———-+————–+————-+———–+————-+———-+——–+—-+
  6. | test3 |          0 | PRIMARY  |        1  |    id          |     A     |   0          |     NULL |
  7. NULL   |     | BTREE      |         |
  8. +——-+————+———-+————–+————-+———–+————-+———-+——–+——+

 

Table:表名

Key_name:什么类型索引(这了是主键)

Column_name:索引列的字段名

Cardinality:索引基数,很关键的一个参数,平均数值组=索引基数/表总数据行,平均数值组越接近1就越有可能利用索引

Index_type:如果索引是全文索引,则是fulltext,这里是b+tree索引,b+tre也是这篇文章研究的重点之一

其他的就不详细介绍,更多:

第二部分:MYISAM和INNODB索引结构

1、 简单介绍B-tree B+ tree树

B-tree结构视图

 

一棵m阶的B-tree树,则有以下性质

(1)Ki表示关键字值,上图中,k1<k2<…<ki<k0<Kn(可以看出,一个节点的左子节点关键字值<该关键字值<右子节点关键字值)

(2)Pi表示指向子节点的指针,左指针指向左子节点,右指针指向右子节点。即是:p1[指向值]<k1<p2[指向值]<k2……

(3)所有关键字必须唯一值(这也是创建myisam 和innodb表必须要主键的原因),每个节点包含一个说明该节点多少个关键字,如上图第二行的i和n

(4)节点:

l  每个节点最可以有m个子节点。

l  根节点若非叶子节点,至少2个子节点,最多m个子节点

l  每个非根,非叶子节点至少[m/2]子节点或叫子树([]表示向上取整),最多m个子节点

(5)关键字:

l  根节点的关键字个数1~m-1

l  非根非叶子节点的关键字个数[m/2]-1~m-1,如m=3,则该类节点关键字个数:2-1~2

(6)关键字数k和指向子节点个数指针p的关系:

l  k+1=p ,注意根据储存数据的具体需求,左右指针为空时要有标志位表示没有

 

B+tree结构示意图如下:

 

B+树是B-树的变体,也是一种多路搜索树:

l  非叶子结点的子树指针与关键字个数相同

l  为所有叶子结点增加一个链指针(红点标志的箭头)

 

 

B+树是B-树的变体,也是一种多路搜索树:

l  非叶子结点的子树指针与关键字个数相同

l  为所有叶子结点增加一个链指针(红点标志的箭头)

2、 MyisAM索引结构

MyisAM索引用的B+tree来储存数据,MyisAM索引的指针指向的是键值的地址,地址存储的是数据,如下图:

(1)结构讲解:上图3阶树,主键是Col2,Col值就是改行数据保存的物理地址,其中红色部分是说明标注。

l  1标注部分也许会迷惑,前面不是说关键字15右指针的指向键值要大于15,怎么下面还有15关键字?因为B+tree的所以叶子节点包含所有关键字且是按照升序排列(主键索引唯一,辅助索引可以不唯一),所以等于关键字的数据值在右子树

l  2标注是相应关键字存储对应数据的物理地址,注意这也是之后和InnoDB索引不同的地方之一

l  2标注也是一个所说MyiAM表的索引和数据是分离的,索引保存在”表名.MYI”文件内,而数据保存在“表名.MYD”文件内,2标注的物理地址就是“表名.MYD”文件内相应数据的物理地址。(InnoDB表的索引文件和数据文件在一起)

l  辅助索引和主键索引没什么大的区别,辅助索引的索引值是可以重复的(但InnoDB辅助索引和主键索引有很明显的区别,这里先提醒注意一下)

3、 Annode索引结构

 

(1)首先有一个表,内容和主键索引结构如下两图:

Col1

Col2

Col3

1

15

phpben

2

20

mhycoe

3

23

phpyu

4

25

bearpa

5

40

phpgoo

6

45

phphao

7

48

phpxue

……

结构上:由上图可以看出InnoDB的索引结构很MyisAM的有很明显的区别

l  MyisAM表的索引和数据是分开的,用指针指向数据的物理地址,而InnoDB表中索引和数据是储存在一起。看红框1可一看出一行数据都保存了。

l  还有一个上图多了三行的隐藏数据列(虚线表),这是因为MyisAM不支持事务,InnoDB处理事务在性能上并发控制上比较好,看图中的红框2中的DB_TRX_ID是事务ID,自动增长;db_roll_ptr是回滚指针,用于事务出错时数据回滚恢复;db_row_id是记录行号,这个值其实在主键索引中就是主键值,这里标出重复是为了容易介绍,还有的是若不是主键索引(辅助索引),db_row_id会找表中unique的列作为值,若没有unique列则系统自动创建一个。关于InnoDB跟多事务MVCC点此:http://www.phpben.com/?post=72

(2)加入上表中Col1是主键(下图标错),而Col2是辅助索引,则相应的辅助索引结构图:

 

可以看出InnoDB辅助索引并没有保存相应的所有列数据,而是保存了主键的键值(图中1、2、3….)这样做利弊也是很明显:

l  在已有主键索引,避免数据冗余,同时在修改数据的时候只需修改辅助索引值。

l  但辅助索引查找数据事要检索两次,先找到相应的主键索引值然后在去检索主键索引找到对应的数据。这也是网上很多mysql性能优化时提到的“主键尽可能简短”的原因,主键越长辅助索引也就越大,当然主键索引也越大。

4、 MyisAM索引与InnoDB索引相比较

l MyisAM支持全文索引(FULLTEXT)、压缩索引,InnoDB不支持

l AnnoDB支持事务,MyisAM不支持

l MyisAM顺序储存数据,索引叶子节点保存对应数据行地址,辅助索引很主键索引相差无几;AnnoDB主键节点同时保存数据行,其他辅助索引保存的是主键索引的值

l MyisAM键值分离,索引载入内存(key_buffer_size),数据缓存依赖操作系统;InnoDB键值一起保存,索引与数据一起载入InnoDB缓冲池

l MyisAM主键(唯一)索引按升序来存储存储,InnoDB则不一定

l MyisAM索引的基数值(Cardinality,show index 命令可以看见)是精确的,InnoDB则是估计值。这里涉及到信息统计的知识,MyisAM统计信息是保存磁盘中,在alter表或Analyze table操作更新此信息,而InnoDB则是在表第一次打开的时候估计值保存在缓存区内

l MyisAM处理字符串索引时用增量保存的方式,如第一个索引是‘preform’,第二个是‘preformence’,则第二个保存是‘7,ance‘,这个明显的好处是缩短索引,但是缺陷就是不支持倒序提取索引,必须顺序遍历获取索引

 

 

第三部分:MYSQL优化

mysql优化是一个重大课题之一,这里会重点详细的介绍mysql优化,包括表数据类型选择,sql语句优化,系统配置与维护优化三类。

1、  表数据类型选择

(1) 能小就用小。表数据类型第一个原则是:使用能正确的表示和存储数据的最短类型。这样可以减少对磁盘空间、内存、cpu缓存的使用。

(2)避免用NULL,这个也是网上优化技术博文传的最多的一个。理由是额外增加字节,还有使索引,索引统计和值更复杂。很多还忽略一

个count(列)的问题,count(列)是不会统计列值为null的行数。更多关于NULL可参考:http://www.phpben.com/?post=71

(3) 字符串如何选择char和varchar?一般phper能想到就是char是固定大小,varchar能动态储存数据。这里整理一下这两者的区别:

属性

Char

Varchar

值域大小

最长字符数是255(不是字节),不管什么编码,超过此值则自动截取255个字符保存并没有报错。 65535个字节,开始两位存储长度,超过255个字符,用2位储存长度,否则1位,具体字符长度根据编码来确定,如utf8

则字符最长是21845个

如何处理字符串末尾空格

去掉末尾空格,取值出来比较的时候自动加上进行比较 Version<=4.1,字符串末尾空格被删掉,version>5.0则保留

储存空间

固定空间,比喻char(10)不管字符串是否有10个字符都分配10个字符的空间 Varchar内节约空间,但更新可能发生变化,若varchar(10),开始若储存5个字符,当update成7个时有myisam可能把行拆开,innodb可能分页,这样开销就增大

适用场合

适用于存储很短或固定或长度相似字符,如MD5加密的密码char(33)、昵称char(8)等 当最大长度远大于平均长度并且发生更新的时候。

 

注意当一些英文或数据的时候,最好用每个字符用字节少的类型,如latin1

(4) 整型、整形优先原则

Tinyint、smallint、mediumint、int、bigint,分别需要8、16、24、32、64。

值域范围:-2^(n-1)~ 2^(n-1)-1

很多程序员在设计数据表的时候很习惯的用int,压根不考虑这个问题

笔者建议:能用tinyint的绝不用smallint

误区:int(1) 和int(11)是一样的,唯一区别是mysql客户端显示的时候显示多少位。

整形优先原则:能用整形的不用其他类型替换,如ip可以转换成整形保存,如商品价格‘50.00元’则保存成50

(5)精确度与空间的转换。在存储相同数值范围的数据时,浮点数类型通常都会比DECIMAL类型使用更少的空间。FLOAT字段使用4字节存储

数据。DOUBLE类型需要8 个字节并拥有更高的精确度和更大的数值范围,DECIMAL类型的数据将会转换成DOUBLE类型。

2、  sql语句优化

  1. mysql> create table one (
  2. id smallint(10) not null auto_increment primary key,
  3. username char(8) not null,
  4. password char(4) not null,
  5. `level` tinyint (1) default 0,
  6. last_login char(15) not null,
  7. index(username,password,last_login))engine=innodb;

这是test表,其中id是主键,多列索引(username,password,last_login),里面有10000多条数据.

  1. | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null |
  2.  Index_type | Comment |
  3. +——-+————+———-+————–+————-+———–+————-+———-+——–+——+
  4. | one   |        0 | PRIMARY  |           1 | id          | A         |20242 |  NULL | NULL  |    |
  5.  BTREE     |         |
  6. +——-+————+———-+————–+————-+———–+————-+———-+——–+——+
  7. | one   |        1 | username |            1 | username    | A         |10121 |  NULL | NULL  |     |
  8. BTREE     |         |
  9. +——-+————+———-+————–+————-+———–+————-+———-+——–+——+
  10. | one   |        1 | username |            2 | password    | A         |10121 |  NULL | NULL  | YES  |
  11.  BTREE     |         |
  12. +——-+————+———-+————–+————-+———–+————-+———-+——–+——+
  13. | one   |        1 | username |              3 | last_login  | A         |20242 |  NULL | NULL  |     |
  14.  BTREE      |         |
  15. +——-+————+———-+————–+————-+———–+————-+———-+——–+——+

(1)    最左前缀原则

定义:最左前缀原则指的的是在sql where 字句中一些条件或表达式中出现的列的顺序要保持和多索引的一致或以多列索引顺序出现,只要出现非顺序出现、断层都无法利用到多列索引。

举例说明:上面给出一个多列索引(username,password,last_login),当三列在where中出现的顺序如(username,password,last_login)、(username,password)、(username)才能用到索引,如下面几个顺序(password,last_login)、(passwrod)、(last_login)—这三者不从username开始,(username,last_login)—断层,少了password,都无法利用到索引。

因为B+tree多列索引保存的顺序是按照索引创建的顺序,检索索引时按照此顺序检索

测试:以下测试不精确,这里只是说明如何才能正确按照最左前缀原则使用索引。还有的是以下的测试用的时间0.00sec看不出什么时间区别,因为数据量只有20003条,加上没有在实体机上运行,很多未可预知的影响因素都没考虑进去。当在大数据量,高并发的时候,最左前缀原则对与提高性能方面是不可否认的。

Ps:最左前缀原则中where字句有or出现还是会遍历全表

(1.1)能正确的利用索引

l  Where子句表达式 顺序是(username)

  1. mysql> explain select * from one where username=’abgvwfnt’;
  2. +—-+————-+——-+——+—————+———-+———+——-+——+————-+
  3. | id | select_type | table | type | possible_keys | key      | key_len | ref   |rows | Extra       |
  4. +—-+————-+——-+——+—————+———-+———+——-+——+————-+
  5. |  1 | SIMPLE      | one   | ref  | username      | username | 24      | const |5 | Using where |
  6. +—-+————-+——-+——+—————+———-+———+——-+——+————-+
  7. 1 row in set (0.00 sec)

l  Where子句表达式 顺序是(username,password)

  1. mysql> explain select * from one where username=’abgvwfnt’ and password=’123456′;
  2. +—-+————-+——-+——+—————+———-+———+————-+——+————-+
  3. | id | select_type | table | type | possible_keys | key      | key_len | ref | rows | Extra       |
  4. +—-+————-+——-+——+—————+———-+———+————-+——+————-+
  5. |  1 | SIMPLE      | one   | ref  | username      | username | 43      | const,const |    1 | Using where |
  6. +—-+————-+——-+——+—————+———-+———+————-+——+————-+
  7. 1 row in set (0.00 sec)

l  Where子句表达式 顺序是(username,password, last_login)

  1. mysql> explain select * from one where username=’abgvwfnt’ and password=’123456’and last_login=’1338251170′;
  2. +—-+————-+——-+——+—————+———-+———+——————-+——+————-+
  3. | id | select_type | table | type | possible_keys | key      | key_len | ref| rows | Extra       |
  4. +—-+————-+——-+——+—————+———-+———+——————-+——+————-+
  5. |  1 | SIMPLE   | one   | ref  | username     | username | 83      | const,const,const |    1 | Using where |
  6. +—-+————-+——-+——+—————+———-+———+——————-+——+————-+
  7. 1 row in set (0.00 sec)

上面可以看出type=ref 是多列索引,key_len分别是24、43、83,这说明用到的索引分别是(username), (username,password), (username,password, last_login );row分别是5、1、1检索的数据行都很少,因为这三个查询都按照索引前缀原则,可以利用到索引。

(1.2)不能正确的利用索引

l  Where子句表达式 顺序是(password, last_login)

  1. mysql> explain select * from one where password=’123456’and last_login=’1338251170′;
  2. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows| Extra       |
  4. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  5. |  1 | SIMPLE      | one   | ALL  | NULL          | NULL | NULL    | NULL | 20146 | Using where |
  6. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  7. 1 row in set (0.00 sec)

l  Where 子句表达式顺序是(last_login)

  1. mysql> explain select * from one where last_login=’1338252525′;
  2. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows| Extra       |
  4. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  5. |  1 | SIMPLE      | one   | ALL  | NULL          | NULL | NULL    | NULL | 20146 | Using where |
  6. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  7. 1 row in set (0.00 sec)

以上的两条语句都不是以username开始,这样是用不了索引,通过type=all(全表扫描),key_len=null,rows都很大20146

Ps:one表里只有20003条数据,为什么出现20146,这是优化器对表的一个估算值,不精确的。

l  Where 子句表达式虽然顺序是(username,password, last_login)或(username,password)但第一个是有范围’<’、’>’,’<=’,’>=’等出现

  1. mysql> explain select * from one where username>’abgvwfnt’ and password =’123456’and last_login=’1338251170′;
  2. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows| Extra       |
  4. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  5. |  1 | SIMPLE      | one   | ALL  | username      | NULL | NULL    | NULL | 20146 | Using where |
  6. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  7. 1 row in set (0.00 sec)

这个查询很明显是遍历所有表,一个索引都没用到,非第一列出现范围(password列或last_login列),则能利用索引到首先出现范围的一列,也就是“where username=’abgvwfnt’ and password >’123456’and last_login=’1338251170′;”或则“where username=’abgvwfnt’ and password >’123456’and last_login<‘1338251170’;”索引长度ref_len=43,索引检索到password列,所以考虑多列索引的时候把那些查询语句用的比较的列放在最后(或非第一位)。

l  断层,即是where顺序(username, last_login)

  1. mysql> explain select * from one where username=’abgvwfnt’ and last_login=’1338252525′;
  2. +—-+————-+——-+——+—————+———-+———+——-+——+————-+
  3. | id | select_type | table | type | possible_keys | key      | key_len | ref   | rows | Extra       |
  4. +—-+————-+——-+——+—————+———-+———+——-+——+————-+
  5. |  1 | SIMPLE   | one   | ref  | username   | username | 24     | const |5 | Using where |
  6. +—-+————-+——-+——+—————+———-+———+——-+——+————-+
  7. 1 row in set (0.00 sec)

注意这里的key_len=24=8*3(8是username的长度,3是utf8编码),rows=5,和下面一条sql语句搜索出来一样

  1. mysql>  select * from one where username=’abgvwfnt’;
  2. +——-+———-+———-+——-+————+
  3. | id    | username | password | level | last_login |
  4. +——-+———-+———-+——-+————+
  5. |  3597 | abgvwfnt | 234567   |     0 | 1338251420 |
  6. |  7693 | abgvwfnt | 456789   |     0 | 1338251717 |
  7. | 11789 | abgvwfnt | 456789   |     0 | 1338251992 |
  8. | 15885 | abgvwfnt | 456789   |     0 | 1338252258 |
  9. | 19981 | abgvwfnt | 456789   |     0 | 1338252525 |
  10. +——-+———-+———-+——-+————+
  11. 5 rows in set (0.00 sec)
  12. mysql>  select * from one where username=’abgvwfnt’ and last_login=’1338252525′;
  13. +——-+———-+———-+——-+————+
  14. | id    | username | password | level | last_login |
  15. +——-+———-+———-+——-+————+
  16. | 19981 | abgvwfnt | 456789   |     0 | 1338252525 |
  17. +——-+———-+———-+——-+————+
  18. 1 row in set (0.00 sec)

这个就是要的返回结果,所以可以知道断层(username,last_login),这样只用到username索引,把用到索引的数据再重新检查last_login条件,这个相对全表查询来说还是有性能上优化,这也是很多sql优化文章中提到的where 范围查询要放在最后(这不绝对,但可以利用一部分索引)

(1.3)如果一个查询where子句中确实不需要password列,那就用“补洞”。

  1. mysql> select distinct(password) from one;
  2. +———-+
  3. | password |
  4. +———-+
  5. | 234567   |
  6. | 345678   |
  7. | 456789   |
  8. | 123456   |
  9. +———-+
  10. 4 rows in set (0.08 sec)

可以看出password列中只有这几个值,当然在现实中不可能密码有这么多一样的,再说数据也可能不断更新,这里只是举例说明补洞的方法

  1. mysql> explain select * from one where username=’abgvwfnt’ and password in(‘123456′,’234567′,’345678′,’456789’)
  2. and last_login=’1338251170′;
  3. +—-+————-+——-+——-+—————+———-+———+——+——+————-+
  4. | id | select_type | table | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
  5. +—-+————-+——-+——-+—————+———-+———+——+——+————-+
  6. |  1 | SIMPLE    | one | range | username    | username| 83      | NULL |4 | Using where |
  7. +—-+————-+——-+——-+—————+———-+———+——+——+————-+
  8. 1 row in set (0.00 sec)

可以看出ref=83 所有的索引都用到了,type=range是因为用了in子句。

这个被“补洞”列中的值应该是有限的,可预知的,如性别,其值只有男和女(加多一个不男不女也无妨)。

“补洞”方法也有瓶颈,当很多列,且需要补洞的相应列(可以多列)的值虽有限但很多(如中国城市)的时候,优化器在优化时组合起来的数量是很大,这样的话就要做好基准测试和性能分析,权衡得失,取得一个合理的优化方法。

(1.4)like

  1. mysql> explain select * from one where username like ‘abgvwfnt%’;
  2. +—-+————-+——-+——-+—————+———-+———+——+——+————-+
  3. | id | select_type | table | type  | possible_keys | key      | key_len | ref  |
  4.  rows | Extra       |
  5. +—-+————-+——-+——-+—————+———-+———+——+——+————-+
  6. |  1 | SIMPLE      | one   | range | username      | username | 24      | NULL |
  7.     5 | Using where |
  8. +—-+————-+——-+——-+—————+———-+———+——+——+————-+
  9. 1 row in set (0.00 sec)
  10. mysql> explain select * from one where username like ‘%abgvwfnt%’;
  11. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  12. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows| Extra       |
  13. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  14. |  1 | SIMPLE      | one   | ALL  | NULL          | NULL | NULL    | NULL | 20259 | Using where |
  15. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  16. 1 row in set (0.01 sec)

对比就知道like操作abgvwfnt%能用到索引,%abgvwfnt%用不到

———————————————————————————————

(2)    Order by 优化

(2.1)filesort优化算法.

在mysql version()<4.1之前,优化器采用的是filesort第一种优化算法,先提取键值和指针,排序后再去提取数据,前后要搜索数据两次,第一次若能使用索引则使用,第二次是随机读(当然不同引擎也不同)。mysql version()>=4.1,更新了一个新算法,就是在第一次读的时候也把selcet的列也读出来,然后在sort_buffer_size中排序(不够大则建临时表保存排序顺序),这算法只需要一次读取数据。所以有这个广为人传的一个优化方法,那就是增大sort_buffer_size。Filesort第二种算法要用到更的空间,sort_buffer_size不够大反而会影响速度,所以mysql开发团队定了个变量max_length_for_sort_data,当算法中读出来的需要列的数据的大小超过该变量的值才使用,所以一般性能分析的时候会尝试把max_length_for_sort_data改小。

(2.2)单独order by 用不了索引,索引考虑加where 或加limit

先建一个索引(last_login),建的过程就不给出了

  1. mysql> explain select * from one order by last_login desc;
  2. +—-+————-+——-+——+—————+——+———+——+——-+—————-+
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows
  4.   | Extra          |
  5. +—-+————-+——-+——+—————+——+———+——+——-+—————-+
  6. |  1 | SIMPLE      | one   | ALL  | NULL          | NULL | NULL    | NULL | 2046
  7. 3 | Using filesort |
  8. +—-+————-+——-+——+—————+——+———+——+——-+—————-+
  9. 1 row in set (0.00 sec)
  10. mysql> explain select * from one order by last_login desc limit 10;
  11. +—-+————-+——-+——-+—————+————+———+——+——+——-+
  12. | id | select_type | table | type  | possible_keys | key      | key_len | ref
  13.  | rows | Extra |
  14. +—-+————-+——-+——-+—————+————+———+——+——+——-+
  15. |  1 | SIMPLE   | one   | index | NULL      | last_login  | 4     | NULL
  16.  |   10 |       |
  17. +—-+————-+——-+——-+—————+————+———+——+——+——-+
  18. 1 row in set (0.00 sec)

开始没limit查询是遍历表的,加了limit后,索引可以使用,看key_len 和key

(2.3)where + orerby 类型,where满足最左前缀原则,且orderby的列和where子句用到的索引的列的子集。即是(a,b,c)索引,where满足最左前缀原则且order by中列a、b、c的任意组合

  1. mysql> explain select * from one where username=’abgvwfnt’ and password =’123456
  2. ‘ and last_login=’1338251001’ order by password desc,last_login desc;
  3. +—-+————-+——-+——+—————+———-+———+——————-+——+————-+
  4. | id | select_type | table | type | possible_keys | key      | key_len | ref
  5.            | rows | Extra       |
  6. +—-+————-+——-+——+—————+———-+———+——————-+——+————-+
  7. |  1 | SIMPLE      | one   | ref  | username      | username | 83      | const,c
  8. onst,const |    1 | Using where |
  9. +—-+————-+——-+——+—————+———-+———+——————-+——+————-+
  10. 1 row in set (0.00 sec)
  11. mysql> explain select * from one where username=’abgvwfnt’ and password =’123456
  12. ‘ and last_login=’1338251001’ order by password desc,level desc;
  13. +—-+————-+——-+——+—————+———-+———+——————-+——+—————————-+
  14. | id | select_type | table | type | possible_keys | key      | key_len | ref| rows | Extra                       |
  15. +—-+————-+——-+——+—————+———-+———+——————-+——+—————————–+
  16. |  1 | SIMPLE      | one   | ref  | username      | username | 83      | const,c
  17. onst,const |    1 | Using where; Using filesort |
  18. +—-+————-+——-+——+—————+———-+———+——————-+——+—————————–+
  19. 1 row in set (0.00 sec)

上面两条语句明显的区别是多了一个非索引列level的排序,在extra这列对了Using filesort

笔者测试结果:where满足最左前缀且order by中的列是该多列索引的子集时(也就是说orerby中没最左前缀原则限制),不管是否有asc ,desc混合出现,都能用索引来满足order by。

笔者测试过,因为篇幅比较大,这里就不一一列出。

Ps:很优化博文都说order by中的列要where中出现的列(是索引)的顺序一致,笔者认为不够严谨。

(2.3) where + orerby+limit

这个其实也差不多,只要where最左前缀,orderby也正确,limit在此影响不大

(2.4)如何考虑order by来建索引

这个回归到创建索引的问题来,在比较常用的oder by的列和where中常用的列建立多列索引,这样优化起来的广度和扩张性都比较好,当然如果要考虑UNION、JOIN、COUNT、IN等进来就复杂很多了

(3)    隔离列

隔离列是只查询语句中把索引列隔离出来,也就是说不能在语句中把列包含进表达式中,如id+1=2、inet_aton(‘210.38.196.138’)—ip转换成整数、convert(123,char(3))—数字转换成字符串、date函数等mysql内置的大多函数。

非隔离列影响性能很大甚至是致命的,这也就是赶集网石展的《三十六军规》中的一条,虽然他没说明是隔离列。

以下就测试一下:

首先建立一个索引(last_login ),这里就不给出建立的代码了,且把last_login改成整型(这里只是为了方便测试,并不是影响条件)

  1. mysql> explain select * from one where last_login = 8388605;
  2. +—-+————-+——-+——+—————+————+———+——-+——-+————-+
  3. | id | select_type | table | type | possible_keys | key        | key_len | ref | rows  | Extra       |
  4. +—-+————-+——-+——+—————+————+———+——-+——-+————-+
  5. |  1 | SIMPLE      | one   | ref  | last_login    | last_login | 3       | const
  6.  | 1 | Using where |
  7. +—-+————-+——-+——+—————+————+———+——-+——-+————-+
  8. 1 row in set, 1 warning (0.00 sec)

容易看出建的索引已起效

  1. mysql> explain select * from one where last_login +1= 8388606 ;
  2. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows
  4.   | Extra       |
  5. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  6. |  1 | SIMPLE      | one   | ALL  | NULL          | NULL | NULL    | NULL | 2049
  7. 7 | Using where |
  8. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  9. 1 row in set (0.00 sec)

last_login +1=8388608非隔离列的出现导致查找的列20197,说明是遍历整张表且索引不能使用。

这是因为这条语句要找出所有last_login的数据,然后+1再和20197比较,优化器在这方面比较差,性能很差。

所以要尽可能的把列隔离出来,如last_login +1= 8388606改成login_login=8388607,或者把计算、转换等操作先用php函数处理过再传递给mysql服务器

(4)    OR、IN、UNION ALL,可以尝试用UNION ALL

(4.1)or会遍历表就算有索引

  1. mysql> explain select * from one where username = ‘abgvwfnt’ or password=’123456′;
  2. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows|  Extra       |
  4. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  5. |  1 | SIMPLE   | one  | ALL  | username   | NULL | NULL    | NULL | 20259 | Using where |
  6. +—-+————-+——-+——+—————+——+———+——+——-+————-+
  7. 1 row in set (0.00 sec)

(4.2)对于in,这个是有争议的,网上很多优化方案中都提到尽量少用in,这不全面,其实在in里面如果是常量的话,可一大胆的用in,这个也是赶集网石展、阿里hellodab的观点(笔者从微博中获知)。应用hellodab一句话“MySQL用IN效率不好,通常是指in中嵌套一个子查询,因为MySQL的查询重写可能会产生一个不好的执行计划,而如果in里面是常量的话,我认为性能没有任何问题,可以放心使用”———当然对于这个比较的话,没有实战数据的话很难辩解,就算有,影响性能的因素也很多,也许会每个dba都有不同的测试结果.这也签名最左前缀中“补洞”一个方法

(4.3)UNION All 直接返回并集,可以避免去重的开销。之所说“尝试”用UNION All 替代 OR来优化sql语句,因为这不是一直能优化的了,这里只是作为一个方法去尝试。

(5)    索引选择性

索引选择性是不重复的索引值也叫基数(cardinality)表中数据行数的比值,索引选择性=基数/数据行,基数可以通过“show index from 表名”查看。

高索引选择性的好处就是mysql查找匹配的时候可以过滤更多的行,唯一索引的选择性最佳,值为1。

那么对于非唯一索引或者说要被创建索引的列的数据内容很长,那就要选择索引前缀。这里就简单说明一下:

  1. mysql> select count(distinct(username))/count(*)  from one;
  2. +————————————+
  3. | count(distinct(username))/count(*) |
  4. +————————————+
  5. |                             0.2047 |
  6. +————————————+
  7. 1 row in set (0.09 sec)

count(distinct(username))/count(*)就是索引选择性的值,这里0.2太小了。

假如username列数据很长,则可以通过

select count(distinct(concat(first_name, left(last_name, N))/count(*)  from one;测试出接近1的索引选择性,其中N是索引的长度,穷举法去找出N的值,然后再建索引。

(6)    重复或多余索引

很多phper开始都以为建索引相对多点性能就好点,压根没考虑到有些索引是重复的,比如建一个(username),(username,password), (username,password,last_login),很明显第一个索引是重复的,因为后两者都能满足其功能。

要有个意识就是,在满足功能需求的情况下建最少索引。对于INNODB引擎的索引来说,每次修改数据都要把主键索引,辅助索引中相应索引值修改,这可能会出现大量数据迁移,分页,以及碎片的出现。

3、系统配置与维护优化

(1)    重要的一些变量

l  key_buffer_size索引块缓存区大小, 针对MyISAM存储引擎,该值越大,性能越好.但是超过操作系统能承受的最大值,反而会使mysql变得不稳定. —-这是很重要的参数

l  sort_buffer_size 这是索引在排序缓冲区大小,若排序数据大小超过该值,则创建临时文件,注意和myisam_sort_buffer_size的区别—-这是很重要的参数

l  read_rnd_buffer_size当排序后按排序后的顺序读取行时,则通过该缓冲区读取行,避免搜索硬盘。将该变量设置为较大的值可以大大改进ORDER BY的性能。但是,这是为每个客户端分配的缓冲区,因此你不应将全局变量设置为较大的值。相反,只为需要运行大查询的客户端更改会话变量

l  join_buffer_size用于表间关联(join)的缓存大小

l  tmp_table_size缓存表的大小

l  table_cache允许 MySQL 打开的表的最大个数,并且这些都cache在内存中

l  delay_key_write针对MyISAM存储引擎,延迟更新索引.意思是说,update记录时,先将数据up到磁盘,但不up索引,将索引存在内存里,当表关闭时,将内存索引,写到磁盘

更多参数查看http://www.phpben.com/?post=70

(2)    optimize、Analyze、check、repair维护操作

l  optimize 数据在插入,更新,删除的时候难免一些数据迁移,分页,之后就出现一些碎片,久而久之碎片积累起来影响性能,这就需要DBA定期的优化数据库减少碎片,这就通过optimize命令。

如对MyisAM表操作:optimize table 表名

对于InnoDB表是不支持optimize操作,否则提示“Table does not support optimize, doing recreate + analyze instead”,当然也可以通过命令:alter table one type=innodb; 来替代。

l  Analyze 用来分析和存储表的关键字的分布,使得系统获得准确的统计信息,影响 SQL 的执行计划的生成。对于数据基本没有发生变化的表,是不需要经常进行表分析的。但是如果表的数据量变化很明显,用户感觉实际的执行计划和预期的执行计划不 同的时候,执行一次表分析可能有助于产生预期的执行计划。

Analyze table 表名

l  Check检查表或者视图是否存在错误,对 MyISAM 和 InnoDB 存储引擎的表有作用。对于 MyISAM 存储引擎的表进行表检查,也会同时更新关键字统计数据

l  Repair  optimize需要有足够的硬盘空间,否则可能会破坏表,导致不能操作,那就要用上repair,注意INNODB不支持repair操作

以上的操作出现的都是如下这是check

  1. +———-+——-+————–+————-+
  2. | Table  | Op  | Msg_type| Msg_text |
  3. +———-+——-+————–+————-+
  4. | test.one | check | status  | OK     |
  5. +———-+——-+————–+————-+

其中op是option 可以是repair check optimize,msg_type 表示信息类型,msg_text 表示信息类型,这里就说明表的状态正常。如在innodb表使用repair就出现note | The storage engine for the table doesn’t support repair

注意:以上操作最好在数据库访问量最低的时候操作,因为涉及到很多表锁定,扫描,数据迁移等操作,否则可能导致一些功能无法正常使用甚至数据库崩溃。

(3)表结构的更新与维护

l  改表结构。当要在数据量千万级的数据表中使用alter更改表结构的时候,这是一个棘手问题。一种方法是在低并发低访问量的时候用平常的alter更改表。另外一种就是建另一个与要修改的表,这个表除了要修改的结构属性外其他的和原表一模一样,这样就能得到一个相应的.frm文件,然后用flush with read lock 锁定读,然后覆盖用新建的.frm文件覆盖原表的.frm,最后unlock table 释放表。

l  建立新的索引。一般方法这里不说。

1、  创建没索引的a表,导入数据形成.MYD文件。

2、  创建包括索引b表,形成.FRM和.MYI文件

3、  锁定读写

4、  把b表的.FRM和.MYI文件改成a表名字

5、  解锁

6、  用repair创建索引。

这个方法对于大表也是很有效的。这也是为什么很多dba坚持说“先导数据库在建索引,这样效率更快”

l  定期检查mysql服务器

定期使用show status、show processlist等命令检查数据库。这里就不细说,这说起来也篇幅是比较大的,笔者对这个也不是很了解

第四部分:图说mysql查询执行流程

1、  查询缓存,判断sql语句是否完全匹配,再判断是否有权限,两个判断为假则到解析器解析语句,为真则提取数据结果返回给用户。

2、  解析器解析。解析器先词法分析,语法分析,检查错误比如引号有没闭合等,然后生成解析树。

3、  预处理。预处理解决解析器无法决解的语义,如检查表和列是否存在,别名是否有错,生成新的解析树。

4、  优化器做大量的优化操作。

5、  生成执行计划。

6、  查询执行引擎,负责调度引擎获取相应数据

7、  返回结果

文章来源:http://blog.csdn.net/turkeyzhou/article/details/8182636

wordPress 的nginx地址重写

博客的地址重写总是存在问题,今天彻底的解决下,由于采用自定义/xxx/id/这种方式显示url,所以在nginx中添加如下重写功能(代码位置在server中),开始一直报错,以为是自己对nginx的配置不了解,后来终于弄懂了,nginx的配置中对带吗格式要求很高,总结就是“if” 和 括号“(、{”两边都带上空格

location ~* /$ {
if ( -e $request_filename ) {
break;
}
rewrite ^/(.*)$ /index.php?$1;
}

不同颜色的象征意义

红色Red

红色是热烈、冲动、强有力的色彩,它能使肌肉的机能和血液循环加快。由于红色容易引起注意,所以在各种媒体中也被广泛的利用,除了具有较佳的明视效果之外,更被用来传达有活力,积极,热诚,温暖,前进等涵义的企业形象与精神,另外红色也常用来作为警告,危险,禁止,防火等标示用色,人们在一些场合或物品上,看到红色标示时,常不必仔细看内容,及能了解警告危险之意,在工业安全用色中,红色即是警告,危险,禁止,防火的指定色。

大红色一般用来醒目,如红旗、万绿丛中一点红;浅红色一般较为温柔、幼嫩,如:新房的布置、孩童的衣饰等;深红色一般可以作衬托,有比较深沉热烈的感觉。

红色与浅黄色最为匹配,大红色与绿色、橙色、蓝色(尤其是深一点的蓝色)相斥,与奶黄色、灰色为中性搭配。

橙色 Orange

橙色是欢快活泼的光辉色彩,是暖色系中最温暖的色,它使人联想到金色的秋天,丰硕的果实,是一种富足、快乐而幸福的颜色。橙色稍稍混入黑色或白色,会变成一种稳重、含蓄又明快的暖色,但混入较多的黑色,就成为一种烧焦的色;橙色中加入较多的白色会带来一种甜腻的感觉。

橙色明视度高,在工业安全用色中,橙色即是警戒色,如火车头,登山服装,背包,救生衣等,橙色一般可作为喜庆的颜色,同时也可作富贵色,如皇宫里的许多装饰。橙色可作餐厅的布置色,据说在餐厅里多用橙色可以增加食欲。

橙色与浅绿色和浅蓝色相配,可以构成最响亮、最欢乐的色彩。橙色与淡黄色相配有一种很舒服的过渡感。橙色一般不能与紫色或深蓝色相配,这将给人一种不干净、晦涩的感觉。由于橙色非常明亮刺眼,有时会使人有负面低俗的意象,这种状况尤其容易发生在服饰的运用上,所以在运用橙色时,要注意选择搭配的色彩和表现方式,才能把橙色明亮活泼具有口感的特性发挥出来。

黄色 Yellow

黄色的灿烂、辉煌,有着太阳般的光辉,象征着照亮黑暗的智慧之光。黄色有着金色的光芒,有象征着财富和权利,它是骄傲的色彩。在工业用色上,黄色常用来警告危险或提醒注意,如交通标志上的黄灯,工程用的大型机器,学生用雨衣,雨鞋等,都使用黄色。黄色在黑色和紫色的衬托下可以达到力量的无限扩大,淡淡的粉红色也可以像少女一样将黄色这骄傲的王子征服。黄色与绿色相配,显得很有朝气,有活力;黄色与蓝色相配,显得美丽、清新;淡黄色与深黄色相配显得最为高雅。

淡黄色几乎能与所有的颜色相配,但如果要醒目,不能放在其它的浅色上,尤其是白色,因为它将是你什么也看不见。深黄色一般不能与深红色及深紫色相配,也不适合与黑色相配,因为它会使人感到晦涩和垃圾箱的感觉。

绿色 Green

在商业设计中,绿色所传达的清爽,理想,希望,生长的意象,符合了服务业,卫生保健业的诉求,在工厂中为了避免*作时眼睛疲劳,许多工作的机械也是采用绿色,一般的医疗机构场所,也常采用绿色来作空间色彩规划即标示医疗用品。

鲜艳的绿色是一种非常美丽、优雅的颜色,它生机勃勃,象征着生命。绿色宽容、大度,几乎能容纳所有的颜色。绿色的用途极为广阔,无论是童年、青年、中年、还是老年,使用绿色决不失其活泼、大方。在各种绘画、装饰中都离不开绿色,绿色还可以作为一种休闲的颜色。

绿色中渗入黄色为黄绿色,它单纯、年轻;绿色中渗入蓝色为蓝绿色,它清秀、豁达。含灰的绿色,仍是一种宁静、平和的色彩,就像暮色中的森林或晨雾中的田野。深绿色和浅绿色相配有一种和谐、安宁的感觉;绿色与白色相配,显得很年轻;浅绿色与黑色相配,显得美丽、大方。绿色与浅红色相配,象征着春天的到来。但深绿色一般不与深红色及紫红色相配,那样会有杂乱、不洁之感。

蓝色 Blue

蓝色是博大的色彩,天空和大海这辽阔的景色都呈蔚蓝色。蓝色是永恒的象征,它是最冷的色彩。纯净的蓝色表现出一种美丽、文静、 理智、安祥与洁净。

由于蓝色沉稳的特性,具有理智,准确的意象,在商业设计中,强调科技,效率的商品或企业形象,大多选用蓝色当标准色,企业色,如电脑,汽车,影印机,摄影器材等等,另外蓝色也代表忧郁,这是受了西方文化的影响,这个意象也运用在文学作品或感性诉求的商业设计中。

蓝色的用途很广,蓝色可以安定情绪,天蓝色可用作医院、卫生设备的装饰,或者夏日的衣饰、窗帘等。在一般的绘画及各类饰品也决离不开蓝色。

不同的蓝色与白色相配,表现出明朗、清爽与洁净;蓝色与黄色相配,对比度大,较为明快;大块的蓝色一般不与绿色相配,它们只能互相渗入,变成蓝绿色、湖蓝色或青色,这也是令人陶醉的颜色;浅绿色与黑色相配,显得庄重、老成、有修养。深蓝色不能与深红色、紫红色、深棕色与黑色相配,因为这样既无对比度,也无明快度,只有一种赃兮兮、乱糟糟的感觉。

紫色 purple

由于具有强烈的女性化性格,在商业设计用色中,紫色也受到相当的限制,除了和女性有关的商品或企业形象之外,其他类的设计不常采用为主色。

紫色是波长最短的可见光波。紫色是非知觉的色,它美丽而又神秘,给人深刻的印象,它既富有威胁性,又富有鼓舞性。紫色是象征虔诚的色相,当光明与理解照亮了蒙昧的虔诚之色时,优美可爱的晕色就会使人心醉!

用紫色表现孤独与献身,用紫红色表现神圣的爱与精神的统辖领域,这就是紫色带来的表现价值。

紫色处于冷暖之间游离不定的状态,加上它的低明度性质,构成了这一色彩心理上的消极感。与黄色不同,紫色不能容纳许多色彩,但它可以容纳许多淡化的层次,一个暗的纯紫色只要加入少量的白色,就会成为一种十分优美、柔和的色彩。随着白色的不断加入,产生出许多层次的淡紫色,而每一层次的淡紫色,都显得那样柔美、动人。

褐色 brown

褐色通常用来表现原始材料的质感,如麻,木材,竹片,软木等,或用来传达某些饮品原料的色泽即味感,如咖啡,茶,麦类等,或强调格调古典优雅的企业或商品形象。

白色 white

白色具有高级,科技的意象,通常需和其他色彩搭配使用,纯白色会带给别人寒冷,严峻的感觉,所以在使用白色时,都会掺一些其他的色彩,如象牙白,米白,乳白,苹果白,在生活用品,服饰用色上,白色是永远流行的主要色,可以和任何颜色作搭配。

黑色 Black

黑色具有高贵,稳重,科技的意象,许多科技产品的用色,如电视,跑车,摄影机,音响,仪器的色彩,大多采用黑色,在其他方面,黑色的庄严的意象,也常用在一些特殊场合的空间设计,生活用品和服饰设计大多利用黑色来塑造高贵的形象,也是一种永远流行的主要颜色,适合和许多色彩作搭配。

灰色 Gray

灰色具有柔和,高雅的意象,而且属于中间性格,男女皆能接受,所以灰色也是永远流行的主要颜色,在许多的高科技产品,尤其是和金属材料有关的,几乎都采用灰色来传达高级,科技的形象,使用灰色时,大多利用不同的层次变化组合或他配其他色彩,才不会过单一,沉闷,而有呆板,僵硬的感觉。

黑色与白色是对色彩的最后抽象,代表色彩世界的阴极和阳极。太极图案就是以黑、白两色的循环形式来表现宇宙永恒的运动的。黑色意味着空无,像太阳的毁灭,像永恒的沉默,没有未来,失去希望。而白色的沉默是有无穷的可能。黑白两色是极端对立的色,它们又总是以对方的存在显示自身的力量。它们似乎是整个色彩世界的主宰。

在色彩体系中灰色恐怕是最被动的色彩了,它是彻底的中性色,依靠邻近的色彩获得生命。灰色意味着一切色彩对比的消失,是视觉最安稳的休息点。然而,人眼不能长久地、无限地注视着灰色,因为无休止的休息意味着死亡。

黑、白、灰在色彩配色中占有相当主要的地位,它们活跃在各种配色中,最大限度地改变对方的明度、亮度与色相,产生出多层次、多品种的优美色彩,因此它们是决不可忽视的无彩色。

2.不同颜色水晶所代表的含义(ZT)
无色水晶:代表纯洁、无私。能提升人的

灵气,驱除杂念。

紫色水晶:代表浪漫、姻缘。颜色高贵。

黄色水晶:代表财富、鸿运。

茶色水晶:代表稳健、安泰。

绿色水晶:代表正义、发展。

绿幽灵水晶:代表财路正、事业兴。

白幽灵水晶:代表清净,供灵修。

红幽灵水晶:代表事业发达,财运兴旺。

金发晶:至美、至尊。

红发晶:热烈、活泼。

黄发晶:红火、兴旺。

黑发晶:偏财、解厄。

绿发晶:幸福、好运。

银发晶:材旺、辟邪。

金字塔水晶:聚集能量、趋吉避凶。

水胆水晶:神奇、灵异。

风光水晶:自然缩影,沟通人与自然的窗口。
3.自然中的颜色代表:
红色 激情 性感
绿色 生命 健康
紫色 高贵 神秘
黑色 深沉
蓝色 洁净 忧郁
橙色 热情
4.生活中的颜色代表:

绿色——稳重和舒适
蓝色——产生遐想
黄色——象征健康
橙色——代表活力
白色——感觉洁净
粉色——诠释温柔
红色——燃烧和热情
黑色——高贵并隐藏缺陷
灰色——随和

文章来源:http://zhidao.baidu.com/question/216981202.html

新买的宏基电脑装不了系统

硬盘分区格式对装系统的影响

同学新买的的宏基e1570g的裸机本想装系统,怎么都装不上,分区时出现下面情况,让建立esp或msr分区,与过去的建立主分区和逻辑分区的方式不一样,如下:
55a7357adab44aed00e8805eb21c8701a08bfb21

查了半天资料才知道是由于硬盘默认分区格式为GPT造成的,要将原有的GPT转为MBR的格式(分区格式为GPT的硬盘必须转为分区格式为mbr硬盘才能安装低版本的windows,一般是win8和win7的区别)。下面是搜到的转换方法

在转换之前,首先让我们了解一下什么是GPT?为什么要转换?

GPT:GUID Partition Table (GUID 分区表 磁盘分区样式支持最大卷为 18 EB (exabytes) 并且每磁盘最多有 128 个分区)
我们可以到“磁盘管理”里面,右键点击下方的磁盘型号,看弹出的菜单,若有“转换为GPT磁盘”字样,说明你的硬盘分区是MBR模式;若有“转换为MBR磁盘”字样,说明你的硬盘分区是GPT模式。 不过:如果你安装的是Win7(无论32位还是64位),你的硬盘分区肯定是MBR模式。 如果你安装的是32位的Win8,你的硬盘分区仍然是MBR模式。 只有你安装的是64位的Win8,你的硬盘分区才可能是GPT模式。

1、用哪种模式的分区对系统运行没有影响。 2、如果主板支持UEFI,那么你可以在大于2T的磁盘上使用GPT模式创建分区安装64位操作系统。如果使用了MBR模式,大于2T那部份不可识别,只能浪费。 3、如果主板是传统BIOS,不支持UEFI,那么你只能在不大于2T的磁盘上使用MBR模式安装64位或32位系统。如果使用了2T以上磁盘,大于2T那部份不可识别,只能浪费。而且,无论磁盘是否大于2T,如果运行于GPT模式,那就不能安装任何操作系统。 4、WinXP不能识别GPT磁盘,无法读写GPT磁盘上的数据,但在远程共享时不受影响。

随机预装Win8的电脑,磁盘为GPT格式的,如果需要安装Win7等早期版本系统,需要转换为MBR格式的,使用Diskpart命令即可完成转换。 操作步骤:注意:转换磁盘格式需要清空磁盘中的所有分区和数据,在操作前,请保存好磁盘中所有重要数据。 1.使用Win7光盘或者U盘引导,进入系统安装界面。

2.按Shift + F10打开命令提示符。

3.输入”Diskpart”(不用输入引号,下同),并按回车,进入操作界面

4.输入:”list disk”,查看磁盘信息。注意看磁盘容量来选择。图中465G的Disk 0是硬盘,3852M的Disk 1是用于Win7安装的U盘。

5.输入:”select disk 0”,选择disk 0为当前操作的磁盘

6.输入:”Clean”,清空当前磁盘分区。

7.输入:”convert mbr”,转换为MBR分区。

8.操作完成,关闭此命令提示符窗口,继续按照正常的方法安装Win7系统即可。
扩展知识:convert命令的其它用法:
convert  basic     -将磁盘从动态转换为基本。
convert  dynamic  -将磁盘从基本转换为动态。
convert  gpt      -将磁盘从MBR转换为GPT。
convert  mbr     -将磁盘从GPT转换为MBR。

GPT 参考资料:http://baike.baidu.com/view/10817.htm
MBR 参考资料:http://baike.baidu.com/subview/9485/9079238.htm?fr=aladdin

文章来源:http://www.pc6.com/infoview/Article_61579.html

程序员创业,千万别创成外包

炳叔跟每一位来咨询创业的程序员都讲两个观点:

1.  想发财,多做事。

2.  千万别创业创成外包。

程序员的强项就是做事,把别人的idea变成一段code,做成一个Product。

程序员的弱项是把Product卖出Money。

最常见的程序员创业倒霉孩子,都是目标做一件大事然后IPO,结果,创业创成了技术外包公司。

明明是以前自己领着BAT高薪待遇,偷偷干私活,钱全自己交老婆的好事,愣是变成了自己接私活苦干给员工发工资的屌事。

全公司除了自己玩命干,大家都是来领工资练手刷经验值的酱油,目标都是BAT的Offer。

累得自己完全没时间、没精力去思考,什么是创新?哪些是创新性需求?我创业的目标就是当个小老板吗?

造成这种高智商程序员创业,创成劳动密集型码农的原因有二:

一是创业者对项目的“从产品到市场的可执行性”研究不足。

二是没找“非程序员朋友”去咨询、交流、PK自己的想法。

什么算“非程序员朋友”呢?

就是各种“外行砖家”呗。

外行砖家的作用,就是给你唱反调,逼你调动全身的智商去思考,我怎么才能说服这个白痴呢?我能把这样的白痴变成我的消费者吗?难道说我的项目才是个白痴?

炳叔前两天刚刚给一位程序员当了一次白痴。

他的项目是这样问滴:

炳叔,我是02年上的科大计算机系。和一个同学有一个想法:围绕高等教育的课堂,将教师,学生,课堂管理,课程内容,考核,答疑等环节串起来实现一个平台。

最近也在调研类似的产品,coursera和我们的形态比较接近。但也有一定的差距。我们的想法主要是想通过优化教育课堂教育的环节,吸引老师加入这个平台,从而将学生引入这个平台。

我们没有学校教师的资源,想从产品层面入手,来吸引老师。

我们是想帮助老师解决问题,降低老师的教学的工作复杂度。

炳叔的砖是这样拍滴:

没戏,纯练手项目,最好的结果是做成个小技术外包公司,帮范冰冰艺术学校开发了一个小品视频教学互动APP。

你要知道,在中国,学习分两种:主动学习和被动学习。

主动学习是学生自己掏钱,比如各种MBA、各种新东方、各种国考。

被动学习是学生家长掏钱,比如小升初、高考补习、团队拓展训练管理课程。

你那个项目两头不靠。

算主动学习吧,中国高等教育的国情是:

1.学生主动学习少。

2.老师自主权少。

3.学校体制官僚。

结果是你根本没用户。

算被动学习吧,你需要一个一个、面对面、去拉关系搞定校长搞定老师上你这个项目,那不就是个技术外包公司吗?

还提什么股份期权融资IPO?

 

本文来源:http://bingshu.baijia.baidu.com/article/4655