mysql sqlserver 区别能不能像MySQL那样只装一个server端?

服务器中可以同时安装sql server和mysql吗
服务器中可以同时安装sql server和mysql吗
09-02-12 &匿名提问
 像mysql 这类基于c/s结构的关系型数据库系统虽然代表着目前数据库应用的主流,但却并不能满足所有应用场合的需要。有时我们需要的可能只是一个简单的基于磁盘文件的数据库系统。这样不仅可以避免安装庞大的数据库服务器,而且还可以简化数据库应用程序的设计。berkeley db正是基于这样的思想提出来的。[编辑本段]berkeley db简介  berkeley db是一个开放源代码的内嵌式数据库管理系统,能够为应用程序提供高性能的数据管理服务。应用它程序员只需要调用一些简单的api就可以完成对数据的访问和管理。与常用的数据库管理系统(如mysql和oracle等)有所不同,在berkeley db中并没有数据库服务器的概念。应用程序不需要事先同数据库服务建立起网络连接,而是通过内嵌在程序中的berkeley db函数库来完成对数据的保存、查询、修改和删除等操作。  berkeley db为许多编程语言提供了实用的api接口,包括c、c++、java、perl、tcl、python和php等。所有同数据库相关的操作都由 berkeley db函数库负责统一完成。这样无论是系统中的多个进程,或者是相同进程中的多个线程,都可以在同一时间调用访问数据库的函数。而底层的数据加锁、事务日志和存储管理等都在berkeley db函数库中实现。它们对应用程序来讲是完全透明的。俗话说:“麻雀虽小五脏俱全。”berkeley db函数库本身虽然只有300kb左右,但却能够用来管理多达256tb的数据,并且在许多方面的性能还能够同商业级的数据库系统相抗衡。就拿对数据的并发操作来说,berkeley db能够很轻松地应付几千个用户同时访问同一个数据库的情况。此外,如果想在资源受限的嵌入式系统上进行数据库管理,berkeley db可能就是惟一正确的选择了。  berkeley db作为一种嵌入式数据库系统在许多方面有着独特的优势。首先,由于其应用程序和数据库管理系统运行在相同的进程空间当中,进行数据操作时可以避免繁琐的进程间通信,因此耗费在通信上的开销自然也就降低到了极低程度。其次,berkeley db使用简单的函数调用接口来完成所有的数据库操作,而不是在数据库系统中经常用到的sql语言。这样就避免了对结构化查询语言进行解析和处理所需的开销。[编辑本段]基本概念  berkeley db简化了数据库的操作模式,同时引入了一些新的基本概念,从而使得访问和管理数据库变得相对简单起来。在使用berkeley db提供的函数库编写数据库应用程序之前,有必要先了解以下这些基本概念。  关键字和数据  关 键字(key)和数据(data)是berkeley db用来进行数据库管理的基础,由这两者构成的key/data对(见表1)组成了数据库中的一个基本结构单元,而整个数据库实际上就是由许多这样的结构单元所构成的。通过使用这种方式,开发人员在使用berkeley db提供的api来访问数据库时,只需提供关键字就能够访问到相应的数据。  key        data  sport        football  fruit        orange  drink        beer  表1 key/data对  如果想将第一行中的 “sport”和“football”保存到berkeley db数据库中,可以调用berkeley db函数库提供的数据保存接口。此时“sport”和“football”将分别当成关键字和数据来看待。之后如果需要从数据库中检索出该数据,可以用 “sport”作为关键字进行查询。此时berkeley db提供的接口函数会返回与之对应的数据“football”。  关键字和数据在berkeley db中都是用一个名为dbt的简单结构来表示的。实际上两者都可以是任意长度的二进制数据,而dbt的作用主要是保存相应的内存地址及其长度,其结构如下所示:  typedef struct {  void *  u_int32_  u_int32_  u_int32_  u_int32_  u_int32_  }  在使用berkeley db进行数据管理时,缺省情况下是一个关键字对应于一个数据,但事实上也可以将数据库配置成一个关键字对应于多个数据。[编辑本段]对象句柄  在berkeley db函数库定义的大多数函数都遵循同样的调用原则:首先创建某个结构,然后再调用该结构中的某些方法。从程序设计的角度来讲,这一点同面向对象的设计原则是非常类似的,即先创建某个对象的一个实例,然后再调用该实例的某些方法。正因如此,berkeley db引入了对象句柄的概念来表示实例化后的结构,并且将结构中的成员函数称为该句柄的方法。  对象句柄的引入使得程序员能够完全凭借面向对象的思想,来完成对berkeley db数据库的访问和操作,即使当前使用的是像c这样的结构化语言。例如,对于打开数据库的操作来说,可以调用db的对象句柄所提供的open函数,其原型如下所示:  int db-&open(db *db, db_txn *txnid, const char *file,  const char *database, dbtype type, u_int32_t flags, int mode);[编辑本段]错误处理  对于任何一个函数库来说,如何对错误进行统一的处理都是需要考虑的问题。berkeley db提供的所有函数都遵循同样的错误处理原则,即函数成功执行后返回零,否则的话则返回非零值。  对于系统错误(如磁盘空间不足和访问权限不够等),返回的是一个标准的值;而对于非系统错误,返回的则是一个特定的错误编码。例如,如果在数据库中没有与某个特定关键字所对应的数据,那么在通过该关键字检索数据时就会出现错误。此时函数的返回值将是db_notfound,表示所请求的关键字并没有在数据库中出现。所有标准的errno值都是大于零的,而由berkeley db定义的特殊错误编码则都是小于零的。  要求程序员记住所有的 错误代号既不现实也没有什么实际意义,因为berkeley db提供了相应的函数来获得错误代号所对应的错误描述。一旦有错误发生,只需首先调用db_strerror()函数来获得错误描述信息,然后再调用db -&err()或db-&errx()就可以很轻松地输出格式化后的错误信息。[编辑本段]应用统一的编程接口  使用berkeley db提供的函数来进行数据库的访问和管理并不复杂,在大多数场合下只需按照统一的接口标准进行调用就可以完成最基本的操作。[编辑本段]打开数据库  打开数据库通常要分两步进行:首先调用db_create()函数来创建db结构的一个实例,然后再调用db-&open()函数来完成真正的打开操作。berkeley db将所有对数据库的操作都封装在名为db的结构中。db_create()函数的作用就是创建一个该结构,其原型如下所示:  typedef struct__  int db_create(db **dbp, db_env *dbenv, u_int32_t flags);  将磁盘上保存的文件作为数据库打开是由db-&open()函数来完成的,其原型如下所示:  int db-&open(db *db, db_txn *txnid, const char *file,  const char *database, dbtype type, u_int32_t flags, int mode);  下面这段代码示范了如何创建db对象句柄及如何打开数据库文件:  #include  #include  #include  #include  #include  #define database &demo.db&  /* 以下程序代码的程序头同此*/  int main()  { db *    if ((ret = db_create(&dbp, null, 0)) != 0) {  fprintf(stderr, &db_create: %s\n&, db_strerror(ret));  exit (1);  }  if ((ret = dbp-&open(dbp, null, database, null, db_btree, db_create, 0664)) != 0) {  dbp-&err(dbp, ret, &%s&, database);  exit (1);  }  }  代码首先调用db_create()函数来创建一个db对象句柄。变量dbp在调用成功后将成为数据库句柄,通过它可以完成对底层数据库的配置或访问。接下去调用db-&open()函数打开数据库文件,参数“database”指明对应的磁盘文件名为demo.db;参数“db_btree”表示数据库底层使用的数据结构是b树;而参数“db_create”和“0664”则表明当数据库文件不存在时创建一个新的数据库文件,并且将该文件的属性值设置为0664。  错误处理是在打开数据库时必须的例行检查,这可以通过调用db-&err()函数来完成。其中参数“ret”是在调用berkeley db函数后返回的错误代码,其余参数则用于显示结构化的错误信息。[编辑本段]添加数据  向berkeley db数据库中添加数据可以通过调用db-&put()函数来完成,其原型如下所示:  int db-&put(db *db, db_txn *txnid, dbt *key, dbt *data, u_int32_t flags);  下面这段代码示范了如何向数据库中添加新的数据:  int main()  { db *  dbt key,    if ((ret = db_create(&dbp, null, 0)) != 0) {  fprintf(stderr, &db_create: %s\n&, db_strerror(ret));  exit (1);  }  if ((ret = dbp-&open(dbp,  null, database, null, db_btree, db_create, 0664)) != 0) {  dbp-&err(dbp, ret, &%s&, database);  exit (1);  }  memset(&key, 0, sizeof(key));  memset(&data, 0, sizeof(data));  key.data = &sport&;  key.size = sizeof(&sport&);  data.data = &football&;  data.size = sizeof(&football&);  if ((ret = dbp-&put(dbp, null, &key, &data, 0)) == 0)  printf(&db: %s: key stored.\n&, (char *)key.data);  else  dbp-&err(dbp, ret, &db-&put&);  }  代码首先声明了两个dbt结构变量,并分别用字符串“sport”和“football”进行填充。它们随后作为关键字和数据传递给用来添加数据的db-&put()函数。dbt结构几乎会在所有同数据访问相关的函数中被用到。  在向数据库中添加数据时,如果给定的关键字已经存在,大多数应用会对于已经存在的数据采用覆盖原则。也就是说,如果数据库中已经保存了一个 “sport/basketball”对,再次调用db-&put()函数添加一个“sport/football”对,那么先前保存的那些数据将会被覆盖。但berkeley db允许在调用db-&put()函数时指定参数“db_nooverwrite”,声明不对数据库中已经存在的数据进行覆盖,其代码如下:  if ((ret = dbp-&put(dbp, null, &key, &data, db_nooverwrite)) == 0)  printf(&db: %s: key stored.\n&, (char *)key.data);  else  dbp-&err(dbp, ret, &db-&put&);  一旦给出“db_nooverwrite”标记,如果db-&put()函数在执行过程中发现给出的关键字在数据库中已经存在了,就无法成功地把该key/data对添加到数据库中,于是将返回错误代号“db_keyexist”。[编辑本段]检索数据  从berkeley db数据库中检索数据可以通过调用db-&get()函数来完成,其原型如下所示:  int db-&get(db *db, db_txn *txnid, dbt *key, dbt *data, u_int32_t flags);  下面这段代码示范了如何从数据库中检索出所需的数据:  int main()  { db *  dbt key,    if ((ret = db_create(&dbp, null, 0)) != 0) {  fprintf(stderr, &db_create: %s\n&, db_strerror(ret));  exit (1);  }  if ((ret = dbp-&open(dbp,  null, database, null, db_btree, db_create, 0664)) != 0) {  dbp-&err(dbp, ret, &%s&, database);  exit (1);  }  memset(&key, 0, sizeof(key));  memset(&data, 0, sizeof(data));  key.data = &sport&;  key.size = sizeof(&sport&);  if ((ret = dbp-&get(dbp, null, &key, &data, 0)) == 0)  printf(&db: %s: key retrieved: data was %s.\n&,  (char *)key.data, (char *)data.data);  else  dbp-&err(dbp, ret, &db-&get&);  }  代码同样声明了两个dbt结构变量,并且调用memset()函数对它们的内容清空。虽然berkeley db并不强制要求在进行数据操作之前先清空它们,但出于提高代码质量考虑还是建议先进行清空操作。在进行数据检索时,对db-&get()函数的返回值进行处理是必不可少的,因为它携带着检索操作是否成功完成等信息。下面列出的是db-&get()函数的返回值:  ◆ 0 函数调用成功,指定的关键字被找到;  ◆ db_notfound 函数调用成功,但指定的关键字未被找到;  ◆大于0 函数调用失败,可能出现了系统错误。[编辑本段]删除数据  从berkeley db数据库中删除数据可以通过调用db-&del()函数来完成,其原型如下所示:  int db-&del(db *db, db_txn *txnid, dbt *key, u_int32_t flags);  下面这段代码示范了如何从数据库中删除数据:  int main()  { db *      if ((ret = db_create(&dbp, null, 0)) != 0) {  fprintf(stderr, &db_create: %s\n&, db_strerror(ret));  exit (1);  }  if ((ret = dbp-&open(dbp,  null, database, null, db_btree, db_create, 0664)) != 0) {  dbp-&err(dbp, ret, &%s&, database);  exit (1);  }  memset(&key, 0, sizeof(key));  key.data = &sport&;  key.size = sizeof(&sport&);  if ((ret = dbp-&del(dbp, null, &key, 0)) == 0)  printf(&db: %s: key was deleted.\n&, (char *)key.data);  else  dbp-&err(dbp, ret, &db-&del&);  }  删除数据只需给出相应的关键字,不用指明与之对应的数据。[编辑本段]关闭数据库  对 于一次完整的数据库操作过程来说,关闭数据库是不可或缺的一个环节。这是因为berkeley db需要依赖于系统底层的缓冲机制,也就是说只有在数据库正常关闭的时候,修改后的数据才有可能全部写到磁盘上,同时它所占用的资源也才能真正被全部释放。关闭数据库的操作是通过调用db-&close()函数来完成的,其原型如下所示:  int db-&close(db *db, u_int32_t flags);  下面这段代码示范了如何在需要的时候关闭数据库:  int main()  { db *  dbt key,  int ret, t_  if ((ret = db_create(&dbp, null, 0)) != 0) {  fprintf(stderr, &db_create: %s\n&, db_strerror(ret));  exit (1);  }  if ((ret = dbp-&open(dbp,  null, database, null, db_btree, db_create, 0664)) != 0) {  dbp-&err(dbp, ret, &%s&, database);    }  memset(&key, 0, sizeof(key));  memset(&data, 0, sizeof(data));  key.data = &sport&;  key.size = sizeof(&sport&);  if ((ret = dbp-&get(dbp, null, &key, &data, 0)) == 0)  printf(&db: %s: key retrieved: data was %s.\n&,  (char *)key.data, (char *)data.data);  else  dbp-&err(dbp, ret, &db-&get&);  if ((t_ret = dbp-&close(dbp, 0)) != 0 && ret == 0)  ret = t_  exit(ret);  }[编辑本段]小结  berkeley db这个嵌入式数据库系统使用非常简单。它没有数据库服务器的概念,也不需要复杂的sql语句,所有对数据的操作和管理都可以通过函数调用来完成,非常适合于那些需要对数据进行简单管理的应用场合  include &db.h&  #include &string.h&  #include &stdlib.h&  #define MAXBUFFER 300  #define MAXSTRING 100  void getdata(void);  /* Declare our struct */  struct example_structure {  float myF  int myI  char *myS  };  typedef struct example_structure EXAMPLE_STRUCTURE;  char SAMPLE_KEY[] = &eins&;  char * Database = &./sample.db&;  DBT sampleKEY;  /*  * Program to illustrate marshalling and unmarshalling structures.  *  * Marshalling is the process of moving the contents of a structure's  * fields into a single contiguous memory location. This is done so that  * the structure can be stored in a Berkeley DB database.  *  * Unmarshalling is performed to take data retrieved from a Berkeley DB database  * and place it back into the structure so that it can be used by the  * application.  */  int  main(void)  {  DBT sampleDBT; /* The Berkeley DB data structure that we use to store data  * in a database. Typically there are two of these for  * every database record, one for a key and one for the  * data. In this case, we need only one DBT for  * illustration purposes.  */  DB *  char *SerialN    EXAMPLE_STRUCTURE myS /* The structure we want to store */  int buffer_ /* The amount of data stored in our buffer */  char buffer[MAXBUFFER]; /* The buffer itself */  char *bufferP /* A pointer into the buffer */  memset(&sampleKEY, 0, sizeof(DBT));  memset(&sampleDBT, 0, sizeof(DBT));  /* First, we fill in our structure's data fields */  myStruct.myFloat = 3.04;  myStruct.myInt = 200;  /* malloc space for the string */  myStruct.myString = (char *)malloc(MAXSTRING * sizeof(char));  /* Copy a string into that space. */  strcpy(myStruct.myString, &My example string.&);  /*  * In order to store the data for this structure, we must make sure that  * all its data is lined up in a single contiguous block of memory -- that  * is, in a single buffer. We also need to know how much data was put into  * that buffer. To do this, we copy the structure's data into the buffer.  * This is the actual marshalling process.  *  * Note that the order we use to copy the data is not important, except  * that we have to make sure that we unmarshall in the same order. Here  * we mix things up a bit in order to illustrate the concept.  *  * Notice that we keep track of how much data we've placed in the buffer as  * we go. Also, take care to copy each new bit of data to the end of the  * buffer, so as to not overwrite any data previously placed there.  */  /* Initialize the buffer */  memset(&buffer, 0, MAXBUFFER);  /* Copy the struct's int into the buffer */  bufferPtr = &buffer[0];  memcpy(bufferPtr, &(myStruct.myInt), sizeof(int));  buffer_length = sizeof(int);  /* Copy the struct's string into the buffer */  bufferPtr = &buffer[buffer_length];  memcpy(bufferPtr, myStruct.myString,  strlen(myStruct.myString) + 1);  buffer_length += (strlen(myStruct.myString) + 1);  /* Copy the struct's float into the buffer */  bufferPtr = &buffer[buffer_length];  memcpy(bufferPtr, &(myStruct.myFloat), sizeof(float));  buffer_length += sizeof(float);  /*  * We now have a buffer that contains all our data. We also have the size of  * the data contained in that buffer. We can use this buffer with our DBT:  */  sampleDBT.data =  sampleDBT.size = buffer_  sampleKEY.data = SAMPLE_KEY;  sampleKEY.size = sizeof(SAMPLE_KEY);  if ((ret = db_create(&dbp, NULL, 0)) != 0)  {  fprintf(stderr, &db_create: %s\n&, db_strerror(ret));  return(ret);  }  if ((ret = dbp-&open(dbp,  NULL, Database, NULL, DB_BTREE, DB_CREATE, 0664)) != 0)  {  dbp-&err(dbp, ret, &%s&, Database);  return(ret);  }  if ((ret = dbp-&put(dbp, NULL, &sampleKEY, &sampleDBT, 0)) != 0)  {  dbp-&err(dbp, ret, &%s&, Database);  fprintf(stderr, &db_create: %s\n&, db_strerror(ret));  return(ret);  }  //ret = dbp-&close(dbp, 0);  /*  * We can now pass the data DBT to a DB-&put() or DBC-&c_put() call for  * storage in the database. We won't show that here.  */  /*  * Upon retrieval from the database (again, we don't show the actual  * database get() activity), the DBT's data field is pointing to  * a void * buffer that contains exactly the data that we marshalled into  * our buffer above. We now need to only unmarshall that data. To do this,  * we have to remember the order in which we originally marshalled the  * data.  */  /*  * Note that we're reusing the same DBT for unmarshalling process as we used  * to marshall the data. In real-world usage, the two would be different  * as they would almost certainly be declared in different scopes.  */  /*  * Now we can print everything out to prove that the marshalling process  * worked  */  printf(&Original structure:\n&);  printf(&\tmyInt: %i, \tmyFloat: %f\n&, myStruct.myInt, myStruct.myFloat);  printf(&\tmyString: %s\n&, myStruct.myString);  ret = dbp-&close(dbp, 0);  getdata();  return(0);  }  void getdata(void)  {  char *bufferP /* A pointer into the buffer */  EXAMPLE_STRUCTURE newS /* The structure we want to place data into */  DBT sampleDBT;  DB *    memset(&sampleDBT, 0, sizeof(DBT));  if ((ret = db_create(&dbp, NULL, 0)) != 0)  {  fprintf(stderr, &db_create: %s\n&, db_strerror(ret));  }  if ((ret = dbp-&open(dbp,  NULL, Database, NULL, DB_BTREE, DB_CREATE, 0664)) != 0)  {  dbp-&err(dbp, ret, &%s&, Database);  }  if ((ret = dbp-&get(dbp, NULL, &sampleKEY, &sampleDBT, 0)) != 0)  {  dbp-&err(dbp, ret, &%s&, Database);    }  bufferPtr = sampleDBT.  /* First, find the int (the first bit of data that we stored) */  newStruct.myInt = *((int *)bufferPtr);  bufferPtr += sizeof(int);  /* Next, the string */  newStruct.myString = (char *)bufferP  bufferPtr += (strlen(newStruct.myString) + 1);  /* And finally, the float */  newStruct.myFloat = *((float *)bufferPtr);  printf(&\nNew structure (after marshalling and unmarshalling:\n&);  printf(&\tmyInt: %i, \tmyFloat: %f\n&, newStruct.myInt, newStruct.myFloat);  printf(&\tmyString: %s\n&, newStruct.myString);  /* Cleanup */  ret = dbp-&close(dbp, 0);  }  output:  Original structure:  myInt: 200, myFloat: 3.040000  myString: My example string.  New structure (after marshalling and unmarshalling:  myInt: 200, myFloat: 3.040000  myString: My example string.  Press enter to continue...  I did not understand why you would us a u_int32_t for the buffer, and of course you have to either flush the output or close the database connection otherwise nothing is written.  Regards  Friedrich
请登录后再发表评论!达梦7的试用 与SQLSERVER的简单技术对比
达梦数据库公司推出了他们的数据库服务管理平台,可以在该平台使用达梦数据库而无须安装达梦7数据库
说实话,第一眼看到还是感到很高大上的,毕竟ORACLE、MYSQL、SQLSERVER都没有推出数据库试用的云平台
其实其他数据库也应该学习一下达梦,做一个平台让大家有机会学习自家的数据库知识,虽然现在这个时代下载安装包比较容易,不过提供一个平台也是有好处的
达梦数据库文档下载:
达梦数据库使用的SQL语言是DM_SQL
达梦数据库的存储层次结构
有空的朋友可以看一下主页右下角的三个文档
具体的DM_SQL语法和命令大家可以参考DM_SQL.pdf
1、我们先选择一个实例,达梦是这样的,一个实例下面只能挂一个数据库,不像SQLSERVER和MYSQL可以挂多个数据库
我们就选DM1这个实例,Windows的,有一些实例可能有人在用所以你会连接不上,当前会话数那里就显示了哪些实例是有在用的
而且这些实例下面有一些是已经有人建了数据库在上面的了
2、选择完实例之后,我们就可以创建数据库,我们打开新建查询窗口
CREATE TABLESPACE BOOKSHOP DATAFILE 'BOOKSHOP.DBF' SIZE 150
--创建模式和表
CREATE SCHEMA RESOURCES AUTHORIZATION SYSDBA
CREATE TABLE PANYHOLIDAYS
HOLIDAY DATE
)STORAGE(ON BOOKSHOP);
--插入数据
INSERT INTO PANYHOLIDAYS(HOLIDAY)
VALUES('')
INSERT INTO PANYHOLIDAYS(HOLIDAY)
VALUES('')
INSERT INTO PANYHOLIDAYS(HOLIDAY)
VALUES('')
--查询数据
select "HOLIDAY"
from "RESOURCES"."COMPANYHOLIDAYS";
TIPS:如果实在不知道语句怎么写,不用担心,左边的管理器也有生成脚本的功能,只需要选中表然后按右键,弹出右键菜单
不过右下角没有显示您当前连接的是哪个实例哪个库,不是太方便
查看表属性,可以看到表是使用16K的块大小
这个管理平台的基本功能
平台编辑器的功能:语法自动补全、自动格式代码、关键字自动高亮、调试、界面管理跟一个完整的数据库管理工具差不多
缺点是右下角没有显示出当前在使用的实例和数据库名
下面是部分功能截图
新建了数据库和模式之后,马上就可以在左边的树型菜单里看到新建的模式
可以看到当前达梦数据库是运行Windows2003系统上的
达梦里有比较多的系统工作线程,每个系统工作线程各司其职
例如rapply_worker_thread线程,他是日志重做线程,他在备机上进行日志重做,跟SQLSERVER是一样的,SQLSERVER里镜像、复制也有一样功能的线程
管理界面就介绍到这里了,继续讲下去好像偏离这篇文章的主体,大家有兴趣可以继续深入研究
当你对某一个数据库研究得很深入的时候再学习另一种数据库就会发现,大部分原理都是相通的
例如技术实现原理,还有一些概念,只是换了名词已而
1、SQLSERVER的用户自定义函数,在MYSQL和达梦数据库里叫存储函数
2、MYSQL里面的事件(EVENT),就是SQLSERVER里面的作业(JOB)
3、达梦数据库里的动态性能视图,SQLSERVER里叫动态管理视图(DMV)
4、达梦数据库里的归档日志文件,SQLSERVER里的事务日志文件
5、MYSQL和达梦数据库里的表空间类似于SQLSERVER里的文件组
当然,上面的概念比较可能不太准确,如果有错误希望大家指正o(&_&)o&
技术对比一
数据库备份
表空间备份
备份的时候,本人觉得大部分原理跟SQLSERVER都是一样的,备份的时候,SQLSERVER会把活动日志一同放进bak文件里面
目的就是保证事务的一致性,达梦数据库也是一样,联机备份的时候把归档日志写入备份文件
而达梦数据库脱机备份的意思是:因为数据库已经脱机,没有数据变更了,当前数据库里的事务都是一致的,所以这时候就无需把日志写入到备份文件里
表空间备份类似于SQLSERVER的文件/文件组备份,只备份数据库的一部分,备份文件组的时候SQLSERVER也是需要把事务日志写入到BAK文件
保证事务一致性
注意:SQLSERVER没有提供脱机备份功能
技术对比二
数据库还原
SQLERVER在还原的时候也是只支持脱机还原,要求不能有任何连接在连接当前要还原的数据库,保证一致性
在达梦里也有备份链原理,内部的原理应该跟SQLSERVER是一样的,详细参考:《》
在SQLSERVER里也有类似达梦数据库的并行还原技术,在还原数据库的时候企业版的SQLSERVER也是使用了多线程技术进行还原
下面摘抄自《SQLSERVER2012实施与管理实战指南》
企业版的SQLSERVERR会针对上述情况做优化,主要在于下面两点:
1、多线程并行处理重做和回滚
在企业版上,SQLSERVER会启用多线程做重做和回滚操作。这样做的一个好处,是缩短恢复总体时间,
让数据库能够尽早上线
如果在SQLSERVER的errorlog里看到类似下面的信息,就说明SQL正在做一个比较大的恢复
技术对比三
数据库的数据保护,不论Oracle还是SQLSERVER还是MySQL,都有三重含义
第一重是Crash后重新起来,要确保数据不丢失
第二重是数据库告诉应用事务写入成功了,这个事务就得持久化,如果没有告诉应用结果,则还可以丢失;
第三重是主机失败切换时(主从切换),如何表现得和没有切换时的情况一样。
每种数据库都有不同的数据守护技术(数据保护技术)
而每种数据库的数据保护技术都是大同小异的
达梦数据库的数据守护技术
连接服务名里的双IP配置类似于SQLSERVER的连接字符串里指定镜像伙伴,当发生故障转移的时候,自动将程序的连接重定向
SQLSERVER里面使用镜像技术时,C#的连接字符串,Partner=myMirrorServerAddress指定备机地址,故障发生的时候.NET Data Provider
自动重定向连接到备机
Database mirroring
--数据库镜像 连接字符串 C#
Data Source=myServerAFailover Partner=myMirrorServerA
Initial Catalog=myDataBIntegrated Security=T
SQLSERVER里的镜像技术原理,下面摘抄自《SQLSERVER2012实施与管理实战指南》
数据库镜像的基本概念讲得差不多了。那么主体数据库和镜像数据库是如何同步数据的呢?
SQL数据库中任何的数据变化都会先记录到事务日志中,然后才会真正更新数据页面。
而事务日志是先保存在该数据库的日志缓存(log buffer)里,然后将缓冲中的日志固化到磁盘上LDF文件中。
在数据库镜像中,主体服务器在将主体数据库的日志从日志缓存固化到磁盘的同时,
还会使用另一个线程来将日志块(log block)发送到镜像服务器的端点。
当镜像服务器通过端点接收到日志块后,他先将日志块放到镜像数据库的日志缓存里,然后将缓存里的日志固化到磁盘上。
一旦日志块被固化后,镜像服务器会根据日志来对镜像数据库执行&重做(redo)&,最终更新数据页面。
当镜像服务器重做日志时,镜像数据库实际就是在执行日志的前滚操作。
如果重做失败,则镜像服务器通过将数据库至于suspended状态来暂停会话。
DBA必须找到问题的原因并解决问题才能继续会话。
当主体服务器截断或收缩数据库事务日志时,镜像服务器也将在日志的同一点收缩日志。
可以看到,数据库镜像其实就是通过发送日志来保持伙伴之间的同步。
从SQL2008开始,日志块在被主体服务器发送网络之前会做压缩处理。
这麽做的目的是为了提升日志发送和接收的效率,降低日志块传输对网络链路和网络设备所带来的负载。
对应那些异常繁忙的生产系统,这项功能不但降低了由于网络不胜负荷的镜像会话异常中断,
也降低由于网络延迟导致的数据库镜像性能问题,可谓一举两得。
达梦数据库的数据守护技术实际上是对应于SQLSERVER 的Always On技术和镜像技术
SQLSERVER 的Always On技术和镜像技术都是高可用技术,由于每种数据库对一些名词概念都采用自己的叫法
例如SQLSERVER里叫高可用,而MYSQL和ORACLE叫可用性,达梦里面叫数据守护,叫法不同,实际上都是指同一样东西
因为叫法的不同导致有一些ORACLE专家以为SQLSERVER没有可用性的方案和产品
ORACLE:、
SQLSERVER:、
有一些架构是share-disk,而有一些架构是share-nothing的,具体在这里不展开来讲了
有兴趣的朋友可以看一下宋沄剑写的《》
技术对比四
数据库复制
数据库复制不算是数据守护的技术,所以不归到数据守护里面
在SQLSERVER里,有发布数据库、分发数据库、订阅数据库之分
而达梦里面主服务器就是发布库,复制服务器就是分发库,从服务器就是订阅库
达梦数据库的复制结构跟SQLSERVER差不多
技术对比五
上面都说了相同点,现在说一下不同点,但是由于篇幅限制,我这里只说达梦的数据库数据页面的结构是怎样的
达梦数据库的页面有不同的大小,有4K、8K、16K、32K,实际上达梦数据库将数据页面叫数据块
跟ORACLE一样也是叫数据块
达梦数据库在配置文件里设置数据块的大小,重启数据库服务之后,达梦就会读取配置文件新的配置信息(有点类似MYSQL)
在新建表的时候就会根据配置文件来创建数据块
而表的数据类型的长度根据当前数据块的大小的不同而不同
而在SQLSERVER里面,是不能设置数据页面的大小的,每个数据页面的大小都是8K
重头戏:COUNT(*)统计结果行数
大家注意下划线部分!!
SQLSERVER跟达梦是一样的
CREATE TABLE counttb(id INT NULL)
INSERT INTO [dbo].[counttb]
SELECT 1 UNION ALL
SELECT NULL
SELECT COUNT(1),COUNT(*),COUNT(id) FROM [dbo].[counttb]
本人之前也写过一篇,至于哪个观点正确留给大家去思考了
虽然大部分原理一样,但是语法跟数据库的结构还是有一些出入
所以当DBA从一种数据库转型到另一种数据库的时候还是需要一段时间的学习
例如从转到或者转到
本文通过技术对比,可以使大家对达梦数据库的技术含量有一个度,虽然没有实际使用过,最起码了解一下我们国家的自主知识产权的产品还是不错的
实际上,达梦数据库的基本功能:序列、全文索引、策略、表分区。。。
这些该有的功能都有了,大家可以看一下文档,比较一下与ORACLE、SQLSERVER、MYSQL的区别
基本上这些数据库有的功能达梦都有
希望达梦这支国家队能够越来越强大的,在数据库方面使国家能够早日摆脱外国的数据库大佬们的制约
如有不对的地方,欢迎大家拍砖o(&_&)o&
阅读(...) 评论()

我要回帖

更多关于 mysql转sqlserver 的文章

 

随机推荐