colorful

zc qq:1337220912

 

shared_from_this 几个值得注意的地方

shared_from_this()是 enable_shared_from_this<T>的成员 函数,返回shared_ptr<T>。首先需要注意的是,这个函数仅在shared_ptr<T>的构造函数被调用之后才能使 用。原因是enable_shared_from_this::weak_ptr并不在构造函数中设置,而是在shared_ptr<T>的 构造函数中设置。

如下代码是错误的:
  1. class D:public boost::enable_shared_from_this<D>
  2. {
  3. public:
  4.     D()
  5.     {
  6.         boost::shared_ptr<D> p=shared_from_this();
  7.     }
  8. };
复制代码
原 因很简单,在D的构造函数中虽然可以保证enable_shared_from_this<D>的构造函数已经被调用,但正如前面所 说,weak_ptr还没有设置。

如下代码也是错误的:
  1. class D:public boost::enable_shared_from_this<D>
  2. {
  3. public:
  4.     void func()
  5.     {
  6.         boost::shared_ptr<D> p=shared_from_this();
  7.     }
  8. };
  9. void main()
  10. {
  11.     D d;
  12.     d.func();
  13. }
复制代码
错 误原因同上。

如下代码是正确的:
  1. void main()
  2. {
  3.     boost::shared_ptr<D> d(new D);
  4.     d->func();
  5. }
复制代码
这 里boost::shared_ptr<D> d(new D)实际上执行了3个动作:首先调用enable_shared_from_this<D>的构造函数;其次调用D的构造函数;最后调用 shared_ptr<D>的构造函数。是第3个动作设置了enable_shared_from_this<D>的 weak_ptr,而不是第1个动作。这个地方是很违背c++常理和逻辑的,必须小心。

结论是,不要在构造函数中使用shared_from_this;其次,如果要使用shared_ptr,则应该 在所有地方均使用,不能使用D d这种方式,也决不要传递裸指针。   

另一个值得注意的地方是在类的继承树中不能有2个或更多个enable_shared_from_this<T>。例如如下代码是错误的:
  1. class A:public boost::enable_shared_from_this<A>
  2. {
  3. public:
  4.     A():a(1){}
  5.     virtual ~A(){}
  6.     boost::shared_ptr<A> get_ptra(){return shared_from_this();}
  7.     int a;
  8. };
  9. class B:public A,public boost::enable_shared_from_this<B>
  10. {
  11. public:
  12.     B():b(2){}
  13.     boost::shared_ptr<B> get_ptrb()
  14.     {
  15.         return boost::enable_shared_from_this<B>::shared_from_this();
  16.     }
  17.     int b;
  18. };
  19. int _tmain(int argc, _TCHAR* argv[])
  20. {
  21.     {
  22.         boost::shared_ptr<B> x(new B);
  23.         boost::shared_ptr<A> a1 = x->get_ptra();
  24.         boost::shared_ptr<B> b1 = x->get_ptrb();
  25.     }
  26.     return 0;
  27. }
复制代码
注 意上面代码中,B同时拥有2个enable_shared_from_this的基类,一个是 enable_shared_from_this<A>,另一个是enable_shared_from_this<B>。在 boost::shared_ptr<B> x(new B);这行代码中,shared_ptr<B>的构造函数仅会设置2个基类中的一个的weak_ptr。在上面的例子中,仅设置 enable_shared_from_this<A>的。如果修改B的定义为:

class B:public boost::enable_shared_from_this<B>,public A,

则仅设置enable_shared_from_this<B>的weak_ptr。很明显都是错误的。

那么enable_shared_from_this以及shared_ptr为何要如此实现呢?又为什么会有如此怪异的结果呢?

首先考察shared_ptr的构造函数:
  1. template<class Y>
  2. explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
  3. {
  4.     boost::detail::sp_enable_shared_from_this( pn, p, p );
  5. }
  6. template<class T, class Y> void sp_enable_shared_from_this( shared_count const & pn, boost::enable_shared_from_this<T> const * pe, Y const * px )
  7. {
  8.     if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast<Y*>(px), pn);
  9. }
复制代码
注 意这个sp_enable_shared_from_this是一个模板函数,而且仅调用了一次,所以不可能2个 enable_shared_from_this基类的weak_ptr都被赋值。但问题在于,在调换了B的定义之后结果居然是不一样的。这里有一个很隐 秘的编译器BUG。按道理来说,编译器在编译这段代码时,应该注意到无法真正决断该怎么实例化sp_enable_shared_from_this并且 报一个错,但vc 2008并没有报错,而是通过编译了。(g++会在此处报错)

那么正确的解法是怎样的呢?
  1. class B:public A
  2. {
  3. public:
  4.     B():b(2){}
  5.     boost::shared_ptr<B> get_ptrb()
  6.     {
  7.         return boost::dynamic_pointer_cast<B>(shared_from_this());
  8.     }
  9.     int b;
  10. };
复制代码
注 意到这里B并没有直接继承enable_shared_from_this,而是使用dynamic_pointer_cast进行了类型转换。

关于为什么enable_shared_from_this是这样实现的,可以参看作者原文:

Every enable_shared_from_this base contains a weak_ptr, The shared_ptr constructor looks up the enable_shared_from_this base and initializes its weak_ptr accordingly. This doesn't work when there are
two or more enable_shared_from_this bases, though.

I could put the weak_ptr in a virtual polymorphic base. This would force polymorphism on all clients of enable_shared_from_this... probably acceptable. It will also force a dynamic_pointer_cast in every
shared_from_this, and this may be harder to swallow, particularly in cases where RTTI is off. So I'm not sure.

If you do want the above behavior, it's easy to duplicate, as I already responded in my first post on the topic. Just make FooB return dynamic_pointer_cast<B>( FooA() ) and remove the enable_shared_from_this<B>
base (A needs to be made polymorphic, of course).

注意为了让dynamic_pointer_cast能工作,A必须具有虚函数,那么最简单的做法当然是令其析构函 数为虚函数(通常一个class如果希望被继承,析构函数就应该为虚函数)

posted @ 2012-06-22 22:42 多彩人生 阅读(595) | 评论 (0)编辑 收藏

enable_shared_from_this(转载)

在 C++ 中需要自己来处理内存,稍微处理不当,就会存在非常郁闷的内存泄漏问题

 

还好,现在 C++ 中推出了强大的智能指针,即 smart_ptr ,本文先稍微介绍一下 smart_ptr ,然后具体说说 shared_ptr 和 weak_ptr ,特别是 enable_shared_from_this 和 shared_from_this

 

除了标准库中的 auto_ptr 之外

在 boost 或者 tr1 中的 smart_ptr 主要是有下面几种

  • scoped_ptr
  • scoped_array
  • shared_ptr
  • shared_array
  • intrusive_ptr
  • weak_ptr

这些里面最难理解的是综合应用了 weak_ptr 和 shared_ptr 的 enable_shared_from_this 类,在该类中定了成员函数 shared_from_this() ,返回 shared_ptr<T> 。这个函数仅在 shared_ptr<T> 的构造函数被调用之后才能使用。原因是 enable_shared_from_this::weak_ptr 并不在构造函数中设置(此处的构造函数指的是类型 T 的构造函数),而是在 shared_ptr<T> 的构造函数中设置(此处的构造函数指的是类型 shared_ptr<T> 的构造函数)。

 

在下面的代码中:

 

Cpp代码
  1. #include <iostream>   
  2.   
  3. #include <string>   
  4.   
  5.     
  6.   
  7. #include <boost/shared_ptr.hpp>   
  8.   
  9. #include <boost/weak_ptr.hpp>   
  10.   
  11. #include <boost/enable_shared_from_this.hpp>   
  12.   
  13.     
  14.   
  15. using namespace std;   
  16.   
  17.     
  18.   
  19. struct Ansible   
  20.   
  21.   : public boost::enable_shared_from_this<Ansible>   
  22.   
  23. {   
  24.   
  25.     boost::shared_ptr<Ansible> get_shared()   
  26.   
  27.     {   
  28.   
  29.         boost::shared_ptr<Ansible> r(this);   
  30.   
  31.     
  32.   
  33.         return r;   
  34.   
  35.     }   
  36.   
  37.     
  38.   
  39.     ~Ansible()   
  40.   
  41.     {   
  42.   
  43.         cout<<"Destructor"<<endl;   
  44.   
  45.     }   
  46.   
  47. };   
  48.   
  49.     
  50.   
  51. int main(int argc,char* argv[])   
  52.   
  53. {   
  54.   
  55.     boost::shared_ptr<Ansible> a(new Ansible);   
  56.   
  57.     Ansible& r = *a;   
  58.   
  59.     //boost::shared_ptr<Ansible> b = r.get_shared();   
  60.   
  61.     boost::shared_ptr<Ansible> b = r.shared_from_this();   
  62.   
  63.     
  64.   
  65.     cout<<"Reference Number "<<a.use_count()<<" "<<b.use_count()<<endl;   
  66.   
  67.     
  68.   
  69.     return 0;   
  70.   
  71. }  
#include <iostream> #include <string> #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> #include <boost/enable_shared_from_this.hpp> using namespace std; struct Ansible : public boost::enable_shared_from_this<Ansible> { boost::shared_ptr<Ansible> get_shared() { boost::shared_ptr<Ansible> r(this); return r; } ~Ansible() { cout<<"Destructor"<<endl; } }; int main(int argc,char* argv[]) { boost::shared_ptr<Ansible> a(new Ansible); Ansible& r = *a; //boost::shared_ptr<Ansible> b = r.get_shared(); boost::shared_ptr<Ansible> b = r.shared_from_this(); cout<<"Reference Number "<<a.use_count()<<" "<<b.use_count()<<endl; return 0; }

 

若不使用 shared_from_this() 成员函数,则会输出 a 和 b 的 use_count() 都为 1 ,然后调用 2 次类型 Ansible 的析构函数,若添加了该成员函数,在 a 和 b 的 use_count() 输出为 2 ,只是调用一次 Ansible 的析构函数。原因是 enable_shared_from_this 里面在 shared_ptr<T> 的时候构造了一个 weak_ptr 类,而 weak_ptr 只是监视,不增加引用计数

 

(下面是转载: http://huyuguang1976.spaces.live.com/blog/cns!2A9E272E3C33AFF1!185.entry

所以如下代码是错误的:

 

class D:public boost::enable_shared_from_this<D>

{

public:

    D()

    {

        boost::shared_ptr<D> p=shared_from_this();

    }

};

 

原因很简单,在 D 的构造函数中虽然可以保证 enable_shared_from_this<D> 的构造函数已经被调用,但正如前面所说, weak_ptr 还没有设置。

 

如下代码也是错误的:

 

class D:public boost::enable_shared_from_this<D>

{

public:

    void func()

    {

        boost::shared_ptr<D> p=shared_from_this();

    }

};

 

void main()

{

    D d;

    d.func();

}

 

错误原因同上。

 

如下代码是正确的:

 

void main()

{

    boost::shared_ptr<D> d(new D);

    d->func();

}

 

这里 boost::shared_ptr<D> d(new D) 实际上执行了 3 个动作:首先调用 enable_shared_from_this<D> 的构造函数;其次调用 D 的构造函数;最后调用 shared_ptr<D> 的构造函数。是第 3 个动作设置了 enable_shared_from_this<D> 的 weak_ptr ,而不是第 1 个动作。这个地方是很违背 c++ 常理和逻辑的,必须小心。

 

结论是,不要在构造函数中使用 shared_from_this ;其次,如果要使用 shared_ptr ,则应该在所有地方均使用,不能使用 D d 这种方式,也决不要传递裸指针。


另解:::::
struct X

{

         boost::shared_ptr<X> getX()

{

         boost::shared_ptr<X> r ;//????如何实现

         return r;

}

};

 

要得到X的智能指针,只是在对象指针是受shared_ptr保护的基础上的,举例如下:

void test_X()

{

         {

X x;

                  boost::shared_ptr<X> px = x.getX();//错误

}

         {

X* x = new X();

boost::shared_ptr<X> px = x->getX();//错误

}

         {

boost::shared_ptr<X>  x (new X());

boost::shared_ptr<X> px = x->getX();//正确

}

}

posted @ 2012-06-22 22:41 多彩人生 阅读(455) | 评论 (0)编辑 收藏

stl string常用函数

string类的构造函数:
string(const char *s); //用c字符串s初始化
string(int n,char c); //用n个字符c初始化
此外,string类还支持默认构造函数和复制构造函数,如string s1;string s2="hello";都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常

string类的字符操作:
const char &operator[](int n)const;
const char &at(int n)const;
char &operator[](int n);
char &at(int n);
operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问。
const char *data()const;//返回一个非null终止的c字符数组
const char *c_str()const;//返回一个以null终止的c字符串
int copy(char *s, int n, int pos = 0) const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目

string的特性描述:
int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数)
int max_size()const; //返回string对象中可存放的最大字符串的长度
int size()const; //返回当前字符串的大小
int length()const; //返回当前字符串的长度
bool empty()const; //当前字符串是否为空
void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分

string类的输入输出操作:
string类重载运算符operator
>>用于输入,同样重载运算符operator<<用于输出操作。
函数getline(istream
&in,string &s);用于从输入流in中读取字符串到s中,以换行符'\n'分开。

string的赋值:
string &operator=(const string &s);//把字符串s赋给当前字符串
string &assign(const char *s);//用c类型字符串s赋值
string &assign(const char *s,int n);//用c字符串s开始的n个字符赋值
string &assign(const string &s);//把字符串s赋给当前字符串
string &assign(int n,char c);//用n个字符c赋值给当前字符串
string &assign(const string &s,int start,int n);//把字符串s中从start开始的n个字符赋给当前字符串
string &assign(const_iterator first,const_itertor last);//把first和last迭代器之间的部分赋给字符串

string的连接:
string &operator+=(const string &s);//把字符串s连接到当前字符串的结尾
string &append(const char *s); //把c类型字符串s连接到当前字符串结尾
string &append(const char *s,int n);//把c类型字符串s的前n个字符连接到当前字符串结尾
string &append(const string &s); //同operator+=()
string &append(const string &s,int pos,int n);//把字符串s中从pos开始的n个字符连接到当前字符串的结尾
string &append(int n,char c); //在当前字符串结尾添加n个字符c
string &append(const_iterator first,const_iterator last);//把迭代器first和last之间的部分连接到当前字符串的结尾

string的比较:
bool operator==(const string &s1,const string &s2)const;//比较两个字符串是否相等
运算符">","<",">=","<=","!="均被重载用于字符串的比较;
int compare(const string &s) const;//比较当前字符串和s的大小
int compare(int pos, int n,const string &s)const;//比较当前字符串从pos开始的n个字符组成的字符串与s的大小
int compare(int pos, int n,const string &s,int pos2,int n2)const;//比较当前字符串从pos开始的n个字符组成的字符串与s中pos2开始的n2个字符组成的字符串的大小
int compare(const char *s) const;
int compare(int pos, int n,const char *s) const;
int compare(int pos, int n,const char *s, int pos2) const;
compare函数在
>时返回1,<时返回-1==时返回0

string的子串:
string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串


string的交换:
void swap(string &s2); //交换当前字符串与s2的值

string类的查找函数:

int find(char c, int pos = 0) const;//从pos开始查找字符c在当前字符串的位置
int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置
int find(const string &s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
//查找成功时返回所在位置,失败返回string::npos的值

int rfind(char c, int pos = npos) const;//从pos开始从后向前查找字符c在当前串中的位置
int rfind(const char *s, int pos = npos) const;
int rfind(const char *s, int pos, int n = npos) const;
int rfind(const string &s,int pos = npos) const;
//从pos开始从后向前查找字符串s中前n个字符组成的字符串在当前串中的位置,成功返回所在位置,失败时返回string::npos的值

int find_first_of(char c, int pos = 0) const;//从pos开始查找字符c第一次出现的位置
int find_first_of(const char *s, int pos = 0) const;
int find_first_of(const char *s, int pos, int n) const;
int find_first_of(const string &s,int pos = 0) const;
//从pos开始查找当前串中第一个在s的前n个字符组成的数组里的字符的位置。查找失败返回string::npos

int find_first_not_of(char c, int pos = 0) const;
int find_first_not_of(const char *s, int pos = 0) const;
int find_first_not_of(const char *s, int pos,int n) const;
int find_first_not_of(const string &s,int pos = 0) const;
//从当前串中查找第一个不在串s中的字符出现的位置,失败返回string::npos

int find_last_of(char c, int pos = npos) const;
int find_last_of(const char *s, int pos = npos) const;
int find_last_of(const char *s, int pos, int n = npos) const;
int find_last_of(const string &s,int pos = npos) const;

int find_last_not_of(char c, int pos = npos) const;
int find_last_not_of(const char *s, int pos = npos) const;
int find_last_not_of(const char *s, int pos, int n) const;
int find_last_not_of(const string &s,int pos = npos) const;
//find_last_of和find_last_not_of与find_first_of和find_first_not_of相似,只不过是从后向前查找

string类的替换函数:

string &replace(int p0, int n0,const char *s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const char *s, int n);//删除p0开始的n0个字符,然后在p0处插入字符串s的前n个字符
string &replace(int p0, int n0,const string &s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const string &s, int pos, int n);//删除p0开始的n0个字符,然后在p0处插入串s中从pos开始的n个字符
string &replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符,然后在p0处插入n个字符c
string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之间的部分替换为字符串s
string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之间的部分替换为s的前n个字符
string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之间的部分替换为串s
string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之间的部分替换为n个字符c
string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last);//把[first0,last0)之间的部分替换成[first,last)之间的字符串

string类的插入函数:

string &insert(int p0, const char *s);
string &insert(int p0, const char *s, int n);
string &insert(int p0,const string &s);
string &insert(int p0,const string &s, int pos, int n);
//前4个函数在p0位置插入字符串s中pos开始的前n个字符
string &insert(int p0, int n, char c);//此函数在p0处插入n个字符c
iterator insert(iterator it, char c);//在it处插入字符c,返回插入后迭代器的位置
void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first,last)之间的字符
void insert(iterator it, int n, char c);//在it处插入n个字符c

string类的删除函数

iterator erase(iterator first, iterator last);
//删除[first,last)之间的所有字符,返回删除后迭代器的位置
iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置
string &erase(int pos = 0, int n = npos);//删除pos开始的n个字符,返回修改后的字符串

string类的迭代器处理:

string类提供了向前和向后遍历的迭代器iterator,迭代器提供了访问各个字符的语法,类似于指针操作,迭代器不检查范围。
用string::iterator或string::const_iterator声明迭代器变量,const_iterator不允许改变迭代的内容。常用迭代器函数有:
const_iterator begin()
const;
iterator begin();
//返回string的起始位置
const_iterator end()const;
iterator end();
//返回string的最后一个字符后面的位置
const_iterator rbegin()const;
iterator rbegin();
//返回string的最后一个字符的位置
const_iterator rend()const;
iterator rend();
//返回string第一个字符位置的前面
rbegin和rend用于从后向前的迭代访问,通过设置迭代器string::reverse_iterator,string::const_reverse_iterator实现

字符串流处理:

通过定义ostringstream和istringstream变量实现,
<sstream>头文件中
例如:
string input("hello,this is a test");
istringstream
is(input);
string s1,s2,s3,s4;
is>>s1>>s2>>s3>>s4;//s1="hello,this",s2="is",s3="a",s4="test"
ostringstream os;
os
<<s1<<s2<<s3<<s4;
cout
<<os.str();

posted @ 2012-06-20 11:16 多彩人生 阅读(229) | 评论 (0)编辑 收藏

文本模式 二进制模式& 文本文件 二进制文件

这几个概念很常见但是也容易搞混。前两者是相反的意思,后两者是一对。

1. 文本模式(textmode)和二进制模式(binarymode)的区别

0.  无论你用哪种语言进行程序设计,也无论你用哪个函数进行文件操作(库函数也好,直接操作系统API也好),最终的文件打开的操作都是由操作系统来进行的,因此各种语言的情况从本质上来说都是相同的。用二进制模式打开一个文件的时候,文件本身的内容和你编写程序时用函数读到的内容完全相同(或者说和磁盘上的内容完全相同)。但是如果用了文本模式,那么操作系统在将文件内容传给上层程序(库函数,或者是你的程序)时,或者上层程序通过操作系统向文件写入内容时,操作系统都会预先进行一层预处理(或者说转义),具体过程依赖于操作系统的实现。

1.  在unix(包括linux)系统上,一个程序从文件里读数据,它得到的数据就是数据本身,一个一个的字节。然而在windows系统上,一个文件可以 用两种模式打开,二进制模式或者文本模式,在二进制模式下,表现的就像unix系统;然而在文本模式下,会有一个转换。是\n <-------> \r\n之间的转换。具体讲就是将回车符"\r\n"解释成"\n"(读出时),将"\n"解释成"\r\n"(写入时)。总之,在unix系统上,打开文件只有二进制模式,在windows系统上,打开文件有文本模式和二进制模式两种。

2.文本文件与二进制文件的区别:

将文件看作是由一个一个字节(byte) 组成的, 那么文本文件中的每个字节的最高位都是0,也就是说文本文件使用了一个字节中的七位来表示所有的信息,而二进制文件则是将字节中的所有位都用上了。这就是两者的区别;接着,第二个问题就是文件按照文本方式或者二进制方式打开,两者会有什么不同呢?其实不管是二进制文件也好,还是文本文件也好,都是一连串的01,但是打开方式不同,对于这些01的处理也就不同。如果按照文本方式打开,在打开的时候会进行translate,将每个字节转换成ASCII码,而以按照二进制方式打开的话,则不会进行任何的translate;最后就是文本文件和二进制文件在编辑的时候,使用的方式也是不同的。譬如,你在记事本中进行文本编辑的时候,你进行编辑的最小单位是字节(byte);而对二进制文件进行编辑的话,最小单位则是位(bit),当然我们都不会直接通过手工的方式对二进制文件进行编辑了。

从文件编码的方式来看,文件可分为ASCII码文件和二进制码文件两种:
ASCII
文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的ASCII码。例如,数5678的存储形式为: 
ASCII
码: 00110101 00110110 00110111 00111000 
                     ↓          
 ↓      ↓         
  
十进制码:    5     6         7       

共占用4个字节。ASCII码文件可在屏幕上按字符显示,例如源程序文件就是ASCII文件,用DOS命令TYPE可显示文件的内容。由于是按字符显示,因此能读懂文件内容。

二进制文件是按二进制的编码方式来存放文件的。例如,数5678的存储形式为:00010110 00101110 只占二个字节。二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。因此也把这种文件称作流式文件 

posted @ 2012-06-17 22:51 多彩人生 阅读(565) | 评论 (0)编辑 收藏

为数据库建立索引

最普通的情况,是为出现在where子句的字段建一个索引。为方便讲述,我们先建立一个如下的表。
CREATE TABLE mytable (
 id serial primary key,
 category_id int not null default 0,
 user_id int not null default 0,
 adddate int not null default 0
);
如果你在查询时常用类似以下的语句:
 SELECT * FROM mytable WHERE category_id=1;
最直接的应对之道,是为category_id建立一个简单的索引:
 CREATE INDEX mytable_categoryid
 ON mytable (category_id);
OK.如果你有不止一个选择条件呢?例如:
 SELECT * FROM mytable WHERE category_id=1 AND user_id=2;
你的第一反应可能是,再给user_id建立一个索引。不好,这不是一个最佳的方法。你可以建立多重的索引。
CREATE INDEX mytable_categoryid_userid ON mytable (category_id,user_id);
注意到我在命名时的习惯了吗?我使用"表名_字段1名_字段2名"的方式。你很快就会知道我为什么这样做了。
现在你已经为适当的字段建立了索引,不过,还是有点不放心吧,你可能会问,数据库会真正用到这些索引吗?测试一下就OK,对于大多数的数据库来说,这是很容易的,只要使用EXPLAIN命令:
EXPLAIN
 SELECT * FROM mytable
WHERE category_id=1 AND user_id=2;
 This is what Postgres 7.1 returns (exactly as I expected)
 NOTICE: QUERY PLAN:
 Index Scan using mytable_categoryid_userid on
 mytable (cost=0.00..2.02 rows=1 width=16)
EXPLAIN
以上是postgres的数据,可以看到该数据库在查询的时候使用了一个索引(一个好开始),而且它使用的是我创建的第二个索引。看到我上面命名的好处了吧,你马上知道它使用适当的索引了。

接着,来个稍微复杂一点的,如果有个ORDER BY字句呢?不管你信不信,大多数的数据库在使用order by的时候,都将会从索引中受益。
 SELECT * FROM mytable
WHERE category_id=1 AND user_id=2
 ORDER BY adddate DESC;

很简单,就象为where字句中的字段建立一个索引一样,也为ORDER BY的字句中的字段建立一个索引:
 CREATE INDEX mytable_categoryid_userid_adddate
 ON mytable (category_id,user_id,adddate);
 注意: "mytable_categoryid_userid_adddate" 将会被截短为
"mytable_categoryid_userid_addda"
 CREATE
 EXPLAIN SELECT * FROM mytable
WHERE category_id=1 AND user_id=2
 ORDER BY adddate DESC;
 NOTICE: QUERY PLAN:
 Sort (cost=2.03..2.03 rows=1 width=16)
-> Index Scan using mytable_categoryid_userid_addda
 on mytable (cost=0.00..2.02 rows=1 width=16)
 EXPLAIN
看看EXPLAIN的输出,数据库多做了一个我们没有要求的排序,这下知道性能如何受损了吧,看来我们对于数据库的自身运作是有点过于乐观了,那么,给数据库多一点提示吧。
为 了跳过排序这一步,我们并不需要其它另外的索引,只要将查询语句稍微改一下。这里用的是postgres,我们将给该数据库一个额外的提示--在 ORDER BY语句中,加入where语句中的字段。这只是一个技术上的处理,并不是必须的,因为实际上在另外两个字段上,并不会有任何的排序操作,不过如果加 入,postgres将会知道哪些是它应该做的。
 EXPLAIN SELECT * FROM mytable
WHERE category_id=1 AND user_id=2
 ORDER BY category_id DESC,user_id DESC,adddate DESC;
 NOTICE: QUERY PLAN:
 Index Scan Backward using
mytable_categoryid_userid_addda on mytable
 (cost=0.00..2.02 rows=1 width=16)
 EXPLAIN
现在使用我们料想的索引了,而且它还挺聪明,知道可以从索引后面开始读,从而避免了任何的排序。
以 上说得细了一点,不过如果你的数据库非常巨大,并且每日的页面请求达上百万算,我想你会获益良多的。不过,如果你要做更为复杂的查询呢,例如将多张表结合 起来查询,特别是where限制字句中的字段是来自不止一个表格时,应该怎样处理呢?我通常都尽量避免这种做法,因为这样数据库要将各个表中的东西都结合 起来,然后再排除那些不合适的行,搞不好开销会很大。
如果不能避免,你应该查看每张要结合起来的表,并且使用以上的策略来建立索引,然后再用EXPLAIN命令验证一下是否使用了你料想中的索引。如果是的话,就OK。不是的话,你可能要建立临时的表来将他们结合在一起,并且使用适当的索引。
要注意的是,建立太多的索引将会影响更新和插入的速度,因为它需要同样更新每个索引文件。对于一个经常需要更新和插入的表格,就没有必要为一个很少使用的where字句单独建立索引了,对于比较小的表,排序的开销不会很大,也没有必要建立另外的索引。
以 上介绍的只是一些十分基本的东西,其实里面的学问也不少,单凭EXPLAIN我们是不能判定该方法是否就是最优化的,每个数据库都有自己的一些优化器,虽 然可能还不太完善,但是它们都会在查询时对比过哪种方式较快,在某些情况下,建立索引的话也未必会快,例如索引放在一个不连续的存储空间时,这会增加读磁 盘的负担,因此,哪个是最优,应该通过实际的使用环境来检验。
在刚开始的时候,如果表不大,没有必要作索引,我的意见是在需要的时候才作索引,也可用一些命令来优化表,例如MySQL可用"OPTIMIZE TABLE"。
综上所述,在如何为数据库建立恰当的索引方面,你应该有一些基本的概念了。

posted @ 2012-06-09 15:44 多彩人生 阅读(430) | 评论 (0)编辑 收藏

数据库的索引

索引

使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构,例如 employee 表的姓(lname)列。如果要按姓查找特定职员,与必须搜索表中的所有行相比,索引会帮助您更快地获得该信息。

索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引的方式与您使用书籍中的索引的方式很相似:它搜索索引以找到特定值,然后顺指针找到包含该值的行。

在数据库关系图中,您可以在选定表的“索引/键”属性页中创建、编辑或删除每个索引类型。当保存索引所附加到的表,或保存该表所在的关系图时,索引将保存在数据库中。有关详细信息,请参见创建索引。

注意;并非所有的数据库都以相同的方式使用索引。有关更多信息,请参见数据库服务器注意事项,或者查阅数据库文档。

作为通用规则,只有当经常查询索引列中的数据时,才需要在表上创建索引。索引占用磁盘空间,并且降低添加、删除和更新行的速度。在多数情况下,索引用于数据检索的速度优势大大超过它的。

索引列

可以基于数据库表中的单列或多列创建索引。多列索引使您可以区分其中一列可能有相同值的行。

如果经常同时搜索两列或多列或按两列或多列排序时,索引也很有帮助。例如,如果经常在同一查询中为姓和名两列设置判据,那么在这两列上创建多列索引将很有意义。

确定索引的有效性:

  • 检查查询的 WHERE 和 JOIN 子句。在任一子句中包括的每一列都是索引可以选择的对象。
  • 对新索引进行试验以检查它对运行查询性能的影响。
  • 考虑已在表上创建的索引数量。最好避免在单个表上有很多索引。
  • 检查已在表上创建的索引的定义。最好避免包含共享列的重叠索引。
  • 检查某列中唯一数据值的数量,并将该数量与表中的行数进行比较。比较的结果就是该列的可选择性,这有助于确定该列是否适合建立索引,如果适合,确定索引的类型。
索引类型

根据数据库的功能,可以在数据库设计器中创建三种索引:唯一索引、主键索引和聚集索引。有关数据库所支持的索引功能的详细信息,请参见数据库文档。

提示:尽管唯一索引有助于定位信息,但为获得最佳性能结果,建议改用主键或唯一约束。

唯一索引

唯一索引是不允许其中任何两行具有相同索引值的索引。

当现有数据中存在重复的键值时,大多数数据库不允许将新创建的唯一索引与表一起保存。数据库还可能防止添加将在表中创建重复键值的新数据。例如,如果在 employee 表中职员的姓 (lname) 上创建了唯一索引,则任何两个员工都不能同姓。

主键索引

数据库表经常有一列或列组合,其值唯一标识表中的每一行。该列称为表的主键。

在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。

聚集索引

在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。

如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度。

posted @ 2012-06-09 15:23 多彩人生 阅读(342) | 评论 (0)编辑 收藏

PostgreSQL: 数组类型(array) 的使用

http://francs3.blog.163.com/blog/static/405767272011103105752290/
  PostgreSQL 支持数组类型,包括一维数组和多维数组,在某些应用场合数组的应用还是很需要的,
这里简单介绍下一维数组的使用及有关数组函数和操作符的使用。
  
  
--定义数组
mydb=> create table test_array(id serial primary key, phone int8[]);
NOTICE:  CREATE TABLE will create implicit sequence "test_array_id_seq" for serial column "test_array.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "test_array_pkey" for table "test_array"
CREATE TABLE

mydb=> \d test_array
                           Table "mydb.test_array"
 Column |   Type   |                        Modifiers                       
--------+----------+---------------------------------------------------------
 id     | integer  | not null default nextval('test_array_id_seq'::regclass)
 phone  | bigint[] |
Indexes:
    "test_array_pkey" PRIMARY KEY, btree (id)


--数组元素插入有两种方式
mydb=> insert into test_array(phone) values ('{1,2}');
INSERT 0 1
mydb=> insert into test_array(phone) values ('{2,3}');
INSERT 0 1

mydb=> insert into test_array(phone) values (array[3,4,5]);
INSERT 0 1

mydb=> select * From test_array;
 id |  phone 
----+---------
  1 | {1,2}
  2 | {2,3}
  3 | {3,4,5}
(3 rows)


--数组元素的引用
mydb=> select phone  from test_array where id=1;
 phone
-------
 {1,2}
(1 row)

mydb=> select phone[1],phone[2]  from test_array where id=1;
 phone | phone
-------+-------
     1 |     2
    
    
    
一 常见的数组操作(Array Operators)

PostgreSQL: 数组类型(array) 的使用 - francs - My DBA LIFE

 

--equal
mydb=>  select array[1,2]=array[1.1,2.1]::int[];
 ?column?
----------
 t
(1 row)

--not equal
mydb=> select array[1,2] <> array[1,2,3];
 ?column?
----------
 t
(1 row)


--less than
mydb=> select ARRAY[1,2,3] < ARRAY[1,2,4];
 ?column?
----------
 t
(1 row)


--greater than
mydb=> select ARRAY[1,4,3] > ARRAY[1,2,4];
 ?column?
----------
 t
(1 row)


--contains
mydb=> select ARRAY[1,4,3] @> ARRAY[3,1];
 ?column?
----------
 t
(1 row)


--is contained by
mydb=> select ARRAY[2,7] <@ ARRAY[1,7,4,2,6];
 ?column?
----------
 t
(1 row)


--overlap (have elements in common)
mydb=> select ARRAY[1,4,3] && ARRAY[2,1];
 ?column?
----------
 t
    

二 常见数组函数( Array Functions )
--将数据元素追加到数组
mydb=> select array_append(array[2,3,4],5);
 array_append
--------------
 {2,3,4,5}
(1 row)

--连接两个数组
mydb=> select array_cat(array[1,2],array[3,4]);
 array_cat
-----------
 {1,2,3,4}
(1 row)

--获得数组的维度
mydb=> select array_ndims(array[1,2,3]);
 array_ndims
-------------
           1
(1 row)

mydb=> select array_ndims(array[[1,2,3],[4,5,6]]);
 array_ndims
-------------
           2
(1 row)


--获得数组的长度                                 ^
mydb=> select array_length(array[1,2,3],1);
 array_length
--------------
            3
(1 row)

mydb=> select array_length(array[[1,2],[2,3]],1);
 array_length
--------------
            2
(1 row)


三 intarray 模块的数组函数
--获取元素个数据总和
mydb=> select icount(array[1,2]);
 icount
--------
      2
(1 row)

mydb=> select icount(array[[1,2],[2,3]]);
 icount
--------
      4
(1 row)


--排序
mydb=> select sort_asc(array[4,8,7]);
 sort_asc
----------
 {4,7,8}
(1 row)

mydb=> select sort_desc(array[4,8,7]);
 sort_desc
-----------
 {8,7,4}
(1 row)

mydb=> select sort_desc(array[[4,8,7],[8,9,7]]);
     sort_desc    
-------------------
 {{9,8,8},{7,7,4}}
(1 row)


四 intarray 模块的数组操作符

PostgreSQL: 数组类型(array) 的使用 - francs - My DBA LIFE

 

--表数据
mydb=> select * from test_array;
 id |  phone 
----+---------
  1 | {1,2}
  2 | {2,3}
  3 | {3,4,5}
  4 | {4,5,6}
  5 | {4,5,7}
(5 rows)


--查找包括相同元素的记录
mydb=> select id ,phone from test_array where phone && array[1,2]::int8[];
 id | phone
----+-------
  1 | {1,2}
  2 | {2,3}
(2 rows)


--查找数组元素的交集
mydb=> select array[1,2,3] & array[3,4,5];
 ?column?
----------
 {3}
(1 row)


五 索引的使用
  
          数组支持创建 GiST 和 GIN 类型索引,这两类索引的选择要根据场合,简单的说, GIN 类型索引在查询上要比
  GiST 类型索引快,但在 update 的时候要慢些,所以 GIN 类型索引适合表数据不太变化的场合,而 GiST 索引适用
  于表数据经常需要 UPDATE 的场景。

posted @ 2012-06-08 16:04 多彩人生 阅读(1389) | 评论 (0)编辑 收藏

网络传输字序

大多数情况下服务器的环境是固定的,所以一般服务就按自己的字序来传输,而在client作转换,转换成与server一致的就可以了,
如果,你的服务器环境多样,那就要考虑转换成网络字序,便于移植

posted @ 2012-06-02 15:31 多彩人生 阅读(110) | 评论 (0)编辑 收藏

linux 断开某个用户的终端连接

断开某个用户的连接
who 查看用户连接

断开远程用户
fuser -k /dev/pts/x

x为who下看到的这个用户的pts序号

断开本地用户

fuser -k /dev/ttyx

x为who查看到的tty序号

posted @ 2012-05-31 20:14 多彩人生 阅读(882) | 评论 (0)编辑 收藏

error while loading shared libraries的解決方法

 行程式時,如此遇到像下列這種錯誤:
./tests: error while loading shared libraries: xxx.so.0:cannot open shared object file: No such file or directory
那就表示系統不知道xxx.so 放在哪個目錄下。
這個時候就要在/etc/ld.so.conf中加入xxx.so所在的目錄。
 一般而言,有很多so檔會在/usr/local/lib這個目錄下,所以在/etc/ld.so.conf中加入/usr/local/lib這一行,可以解決此問題。
將 /etc/ld.so.conf存檔後,還要執行「/sbin/ldconfig –v」來更新一下才會生效。

posted @ 2012-05-30 19:36 多彩人生 阅读(314) | 评论 (0)编辑 收藏

仅列出标题
共25页: First 12 13 14 15 16 17 18 19 20 Last 

导航

统计

常用链接

留言簿(3)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜