MONO中文MONO平台技术软件开发Database Access(Ado.net) 关于改进版的COMB数据库效率的测试(1)

1  /  1  页   1 跳转 查看:3399

关于改进版的COMB数据库效率的测试(1)

关于改进版的COMB数据库效率的测试(1)

在“The Cost of GUIDs as Primary Keys”

http://www.sinoprise.cn/showtopic-105.aspx)一文中,提出了“COMB”数

据类型的设想,即是将GUID的后6位改为时间,由于原GUID是无序的,这样一来就

便于索引排序,关于为什么采用GUID的后6位,而不是前6位,在原文中有这样一

段描述:

The guess that I had about the problem with the INSERT overhead for

GUIDs was that the lack of order in the Windows 2000–generated GUIDs

was giving SQL Server a hard time administering indexes under massive

INSERT periods. Therefore, I tried to create an order for the GUIDs

instead. I tried to CAST the current DATETIME to a BINARY(8) and put

that first in the GUID. Unfortunately, that had no effect. When I

investigated it further, I found that when I had a BINARY(16) value and

CASTed it to a UNIQUEIDENTIFIER, some bytes were scrambled. What to do?

You guessed it. I tried to compensate for the scrambling to see if that

had any positive effect on throughput, but no effect occurred. Then I

found out that it wasn't the first (high) byte that was important for

the new ordering, but the last (low) bytes. I also learned that I

didn't have to use BINARY(8) for the current DATETIME. BINARY(6) is

enough for the next 77 years, so I decided to occupy only the last

(low) 6 bytes with the current DATETIME. In Listing 5, you can see the

result of PRINT CAST(GETDATE() AS BINARY(8)). The first (high) bytes

are 0.


我曾经做过一次关于效率的测试,使用Delphi+Access做的,“Integer GUID和

Comb做主键的效率测试” (http://www.sinoprise.cn/showtopic-104.aspx),

因为在其他的数据库中,没有所谓的GUID字段,所以应该把GUID(16个字节)转

化为字符串(32个字符),以字符串作为索引和主键,这样就比用整数做主键大

了整整8倍,不用测试,平经验就知道效率肯定赶不上整数做主键,但GUID字符串

做主键在某些应用上还是有优势的,特别是当多个数据库需要同步时,这是自动

加一的整数就忘尘莫及了。

既然字符串做为主键,我还是坚持我的看法,我觉得应该是前边的字符有序更利

于索引,所以这次一如既往,我将GUID的前6个字节替换掉了,这样生成的字符串

有序,在前6个字节中用两个字节表示但前时间距1970-1-1的天数,后4个字节表

示当前时间距0:0:0的时间点数,这样可以精确到1/300秒,我在数据库中做了1

千万条数据,无重复。在内存中用哈希表检测10亿条GUID无重复。按照这个算法

,前6个字节可以保证179.54794520547945205479452054795年无重复。

我的机器配置:

硬件: 迅驰1.8 G CPU,IBM T43 笔记本,2G内存
软件: .NET 1.1, 2.0,3.0,3.5
      使用.NET 2.0测试
        mysql 5.0
        mysql provider 5.1(mysql官方驱动)



mysql数据库结构:

DROP TABLE IF EXISTS `maintable`;
CREATE TABLE `maintable` (
  `szKey` varchar(32) NOT NULL default '',
  `szValue` varchar(32) default NULL,
  PRIMARY KEY  (`szKey`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `subtable`;
CREATE TABLE `subtable` (
  `szKey` varchar(32) NOT NULL default '',
  `szFK` varchar(32) NOT NULL default '',
  `szValue` varchar(32) default NULL,
  PRIMARY KEY  (`szKey`),
  KEY `subtable_fk` (`szFK`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


应用程序界面:
Sinoprise Network Studio
        ----专注.NET技术
 

关于改进版的COMB数据库效率的测试(2)

程序主要算法:

数据插入:

private void button4_Click(object sender, EventArgs e)
              {
                        MySqlConnection      conn;
           


                      string connStr = String.Format("server={0};user

id={1}; password={2}; database={3}; pooling=false",
                              "localhost","root", "root",

"comb_test");

                      try
                      {
                              conn = new MySqlConnection(connStr);
                              conn.Open();

                              MySqlCommand cmd = conn.CreateCommand

();
                              cmd.CommandType = CommandType.Text;
                              int c = (int)numericUpDown2.Value;
                              int r = (int)numericUpDown1.Value;
                              progressBar1.Maximum = c;
                              progressBar2.Maximum = r;

                              DateTime dt1 = DateTime.Now;

                              progressBar1.Value = 0;
                              for (int i=0; i<c; i++)
                              {
                                      string key = GetGuidString();
                                      cmd.CommandText = "insert into

maintable(szKey,szValue) values(\'"+key+"\',\'"+key+"\')";
                                      cmd.ExecuteNonQuery();
                                      progressBar2.Value = 0;
                                      for (int j=0; j<r;j++)
                                      {
                                              string subKey =

GetGuidString();
                                              cmd.CommandText =

"insert into subtable(szKey,szFK,szValue) values

(\'"+subKey+"\',\'"+key+"\',\'"+subKey+"\')";
                                              cmd.ExecuteNonQuery();

                                              progressBar2.Value +=

1;
                                              this.Update();
                                              Application.DoEvents();
                                      }                         
                                      progressBar1.Value += 1;
                                      label3.Text = Convert.ToString

(i + 1) + " / " + Convert.ToString(c);
                              }

                              DateTime dt2 = DateTime.Now;
                              TimeSpan ts = dt2.Subtract(dt1);
                              textBox3.Text = textBox3.Text +

Environment.NewLine
                                      +

"===============================" + Environment.NewLine
                                      + "插入主表记录:" +

Convert.ToString(c) + Environment.NewLine
                                      + "插入从表记录:" +

Convert.ToString(r) + Environment.NewLine
                                      + "插入总记录:" +

Convert.ToString(c * r) + Environment.NewLine
                                      + "耗时:" + Convert.ToString

(ts.TotalMilliseconds / 1000) + " 秒 " + Environment.NewLine
                                      + "平均每条记录耗时:" +

Convert.ToString((ts.TotalMilliseconds / (c * r)) / 1000) +" 秒"+

Environment.NewLine;

                              conn.Close();
                              conn.Dispose();
                      }
                      catch (MySqlException ex)
                      {
                              MessageBox.Show("Error connecting to

the server: " + ex.Message);
                      }

              }
Sinoprise Network Studio
        ----专注.NET技术
 

关于改进版的COMB数据库效率的测试(3)

数据查询:

private void button3_Click(object sender, EventArgs e)
              {
                      MySqlConnection conn;
                      MySqlConnection conn2;
                     


                      string connStr = String.Format("server={0};user

id={1}; password={2}; database={3}; pooling=false",
                              "localhost", "root", "root",

"comb_test");

                      try
                      {
                              conn = new MySqlConnection(connStr);
                              conn2 = new MySqlConnection(connStr);
                              conn.Open();
                              conn2.Open();

                              DateTime dt1;
                              DateTime dt2;
                              TimeSpan ts;

                              MySqlCommand cmd = conn.CreateCommand

();
                              MySqlCommand selCmd =

conn2.CreateCommand();
                              cmd.CommandType = CommandType.Text;
                              selCmd.CommandType = CommandType.Text;
                              MySqlDataReader dr;
                              MySqlDataReader selDr;

                              dt1 = DateTime.Now;
                              cmd.CommandText = "select count(*) as

cc from maintable";
                              long mainTableCount = (long)

cmd.ExecuteScalar();
                              dt2 = DateTime.Now;
                              ts = dt2.Subtract(dt1);
                              textBox3.Text = textBox3.Text +

Environment.NewLine
                                      +

"===============================" + Environment.NewLine
                                      + "主表记录数:" +

Convert.ToString(mainTableCount) + Environment.NewLine
                                      + "Count主表耗时" +

Convert.ToString(ts.TotalMilliseconds / 1000) + " 秒 " +

Environment.NewLine;

                              dt1 = DateTime.Now;
                              cmd.CommandText = "select count(*) as

cc from subtable";
                              long subTableCount = (long)

cmd.ExecuteScalar();
                              dt2 = DateTime.Now;
                              ts = dt2.Subtract(dt1);
                              textBox3.Text = textBox3.Text +

Environment.NewLine
                                      + "从表记录数:" +

Convert.ToString(subTableCount) + Environment.NewLine
                                      + "Count从表耗时" +

Convert.ToString(ts.TotalMilliseconds / 1000) + " 秒 " +

Environment.NewLine;


                              if (mainTableCount > 100)
                                      mainTableCount = 100;
                              progressBar1.Maximum = (int)

mainTableCount;
                              progressBar1.Value = 0;

                             

                              dt1 = DateTime.Now;
                              cmd.CommandText = "select szkey from

maintable order by szkey";
                              dr = cmd.ExecuteReader();
                              dt2 = DateTime.Now;
                              ts = dt2.Subtract(dt1);
                              textBox3.Text = textBox3.Text +

Environment.NewLine
                                      + "主表Select All耗时" +

Convert.ToString(ts.TotalMilliseconds / 1000) + " 秒 " +

Environment.NewLine;
dt1 = DateTime.Now;
                              int i = 0;
                              while (dr.Read())
                              {
                                      selCmd.CommandText = @"
                                                      select

subtable.szkey as subKey,  maintable.szkey asmainkey,
                                                     

maintable.szValue as mainValue, subtable.szvalue as subvalue
                                                      from maintable

inner join subtable on maintable.szkey=subtable.szfk
                                                      where

subtable.szfk='"+(string)dr[0]+"'";
                                      selDr = selCmd.ExecuteReader();
                                      if (!selDr.IsClosed)
                                              selDr.Close();
                                      selDr.Dispose();
                                      selDr =null;                 

         
                                     
                                      progressBar1.Value += 1;
                                      i++;
                                      label3.Text = Convert.ToString

(i) + " / " + Convert.ToString(mainTableCount);
                                      this.Update();
                                      Application.DoEvents();
                                      if (100 == i)
                                              break;
                              }

                              dt2 = DateTime.Now;
                              ts = dt2.Subtract(dt1);
                              textBox3.Text = textBox3.Text +

Environment.NewLine
                                      + "连接搜索:" +

Convert.ToString(mainTableCount) + " 次" +Environment.NewLine
                                      + "主从表连接搜索耗时:" +

Convert.ToString(ts.TotalMilliseconds / 1000) + " 秒 " +

Environment.NewLine
                                      + "平均每条记录耗时:" +

Convert.ToString((ts.TotalMilliseconds / i) / 1000) + "

秒"+Environment.NewLine;

                              conn.Close();
                              conn.Dispose();
                              conn2.Close();
                              conn2.Dispose();
                      }
                      catch (MySqlException ex)
                      {
                              MessageBox.Show("Error connecting to

the server: " + ex.Message);
                      }
              }
Sinoprise Network Studio
        ----专注.NET技术
 

关于改进版的COMB数据库效率的测试(4)

相关的测试数据:

===============================
主表记录数:1000
Count主表耗时0 秒

从表记录数:10000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:1000 次
主从表连接搜索耗时:8.46875 秒
平均每条记录耗时:0.00846875 秒

===============================
插入主表记录:1000
插入从表记录:10
插入总记录:10000
耗时:5.84375 秒
平均每条记录耗时:0.000584375 秒


===============================
插入主表记录:1000
插入从表记录:10
插入总记录:10000
耗时:8.25 秒
平均每条记录耗时:0.000825 秒

===============================
主表记录数:3000
Count主表耗时0 秒

从表记录数:30000
Count从表耗时0 秒

主表Select All耗时0.015625 秒

连接搜索:3000 次
主从表连接搜索耗时:67.390625 秒
平均每条记录耗时:0.0224635416666667 秒

===============================
插入主表记录:1000
插入从表记录:10
插入总记录:10000
耗时:8.71875 秒
平均每条记录耗时:0.000871875 秒

===============================
插入主表记录:1000
插入从表记录:10
插入总记录:10000
耗时:8.234375 秒
平均每条记录耗时:0.0008234375 秒

===============================
主表记录数:5000
Count主表耗时0.015625 秒

从表记录数:50000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:5000 次
主从表连接搜索耗时:173.75 秒
平均每条记录耗时:0.03475 秒


===============================
插入主表记录:1000
插入从表记录:10
插入总记录:10000
耗时:8.25 秒
平均每条记录耗时:0.000825 秒

===============================
主表记录数:3000
Count主表耗时0 秒

从表记录数:30000
Count从表耗时0 秒

主表Select All耗时0.015625 秒

连接搜索:3000 次
主从表连接搜索耗时:67.390625 秒
平均每条记录耗时:0.0224635416666667 秒

===============================
插入主表记录:1000
插入从表记录:10
插入总记录:10000
耗时:8.71875 秒
平均每条记录耗时:0.000871875 秒

===============================
插入主表记录:1000
插入从表记录:10
插入总记录:10000
耗时:8.234375 秒
平均每条记录耗时:0.0008234375 秒

===============================
主表记录数:5000
Count主表耗时0.015625 秒

从表记录数:50000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:5000 次
主从表连接搜索耗时:173.75 秒
平均每条记录耗时:0.03475 秒

===============================
插入主表记录:10000
插入从表记录:5
插入总记录:50000
耗时:51.8125 秒
平均每条记录耗时:0.00103625 秒


===============================
主表记录数:15000
Count主表耗时0 秒

从表记录数:100000
Count从表耗时0 秒

主表Select All耗时0.015625 秒

连接搜索:15000 次
主从表连接搜索耗时:1065.828125 秒
平均每条记录耗时:0.0710552083333333 秒


===============================
插入主表记录:1000
插入从表记录:10
插入总记录:10000
耗时:8.65625 秒
平均每条记录耗时:0.000865625 秒


===============================
主表记录数:16000
Count主表耗时0.015625 秒

从表记录数:110000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:16000 次
主从表连接搜索耗时:1192.90625 秒
平均每条记录耗时:0.074556640625 秒



加大从表的数据量 由 1:10 改为1:100


===============================
插入主表记录:1000
插入从表记录:100
插入总记录:100000
耗时:74.890625 秒
平均每条记录耗时:0.00074890625 秒


===============================
插入主表记录:1000
插入从表记录:100
插入总记录:100000
耗时:75.703125 秒
平均每条记录耗时:0.00075703125 秒

===============================
插入主表记录:10
插入从表记录:1000
插入总记录:10000
耗时:4.625 秒
平均每条记录耗时:0.0004625 秒



改变算法,将主表只能够的主键降序排列,这样在搜索时,搜索从表中的新加进的记录
对主表的遍历,仅遍历100次,去平均值,以便节省测试时的时间

===============================
主表记录数:18010
Count主表耗时0 秒

从表记录数:320000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:19.421875 秒
平均每条记录耗时:0.19421875 秒



===============================
插入主表记录:10000
插入从表记录:10
插入总记录:100000
耗时:63.0625 秒
平均每条记录耗时:0.000630625 秒


===============================
主表记录数:28010
Count主表耗时0 秒

从表记录数:420000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:26.28125 秒
平均每条记录耗时:0.2628125 秒



将数据量提高的从表100万条数据测试


===============================
插入主表记录:500
插入从表记录:1000
插入总记录:500000
耗时:166.359375 秒
平均每条记录耗时:0.00033271875 秒

===============================
主表记录数:28510
Count主表耗时0 秒

从表记录数:920000
Count从表耗时0 秒

主表Select All耗时0.015625 秒

连接搜索:100 次
主从表连接搜索耗时:58.3125 秒
平均每条记录耗时:0.583125 秒



在从表的外键字段上加上索引


加完索引后再次测试

===============================
主表记录数:28510
Count主表耗时0.015625 秒

从表记录数:920000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:0.125 秒
平均每条记录耗时:0.00125 秒



以下数据均为有索引的情况

将数据量提升到200万




===============================
插入主表记录:1005
插入从表记录:1000
插入总记录:1005000
耗时:485.078125 秒
平均每条记录耗时:0.000482664800995025 秒

连续查询大约200万条数据时的效率:




===============================
主表记录数:29515
Count主表耗时0 秒

从表记录数:1925000
Count从表耗时0 秒

主表Select All耗时0.015625 秒

连接搜索:100 次
主从表连接搜索耗时:1.5 秒
平均每条记录耗时:0.015 秒

===============================
主表记录数:29515
Count主表耗时0 秒

从表记录数:1925000
Count从表耗时0 秒

主表Select All耗时0.015625 秒

连接搜索:100 次
主从表连接搜索耗时:1.390625 秒
平均每条记录耗时:0.01390625 秒

===============================
主表记录数:29515
Count主表耗时0 秒

从表记录数:1925000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.453125 秒
平均每条记录耗时:0.01453125 秒

===============================
主表记录数:29515
Count主表耗时0 秒

从表记录数:1925000
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.4375 秒
平均每条记录耗时:0.014375 秒



===============================
主表记录数:29515
Count主表耗时0.265625 秒

从表记录数:1925000
Count从表耗时0.109375 秒

主表Select All耗时0.03125 秒

连接搜索:100 次
主从表连接搜索耗时:6.953125 秒
平均每条记录耗时:0.06953125 秒

===============================
主表记录数:1029565
Count主表耗时0 秒

从表记录数:4925150
Count从表耗时0 秒

主表Select All耗时0.046875 秒

连接搜索:100 次
主从表连接搜索耗时:4.875 秒
平均每条记录耗时:0.04875 秒


===============================
主表记录数:1029565
Count主表耗时0 秒

从表记录数:4925150
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.390625 秒
平均每条记录耗时:0.01390625 秒

===============================
主表记录数:1029565
Count主表耗时0 秒

从表记录数:4925150
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.375 秒
平均每条记录耗时:0.01375 秒


===============================
插入主表记录:5000050
插入从表记录:3
插入总记录:15000150
耗时:10714.375 秒
平均每条记录耗时:0.000714284523821428 秒


===============================
主表记录数:6029615
Count主表耗时0 秒

从表记录数:19925300
Count从表耗时0 秒

主表Select All耗时0.109375 秒

连接搜索:100 次
主从表连接搜索耗时:6.640625 秒
平均每条记录耗时:0.06640625 秒

===============================
主表记录数:6029615
Count主表耗时0 秒

从表记录数:19925300
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.46875 秒
平均每条记录耗时:0.0146875 秒


===============================
主表记录数:6029615
Count主表耗时0 秒

从表记录数:19925300
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.5 秒
平均每条记录耗时:0.015 秒


===============================
主表记录数:6029615
Count主表耗时0 秒

从表记录数:19925300
Count从表耗时0 秒

主表Select All耗时0.015625 秒

连接搜索:100 次
主从表连接搜索耗时:1.453125 秒
平均每条记录耗时:0.01453125 秒

===============================
主表记录数:6029615
Count主表耗时0 秒

从表记录数:19925300
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.515625 秒
平均每条记录耗时:0.01515625 秒

===============================
主表记录数:6029615
Count主表耗时0 秒

从表记录数:19925300
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.4375 秒
平均每条记录耗时:0.014375 秒

===============================
主表记录数:6029615
Count主表耗时0 秒

从表记录数:19925300
Count从表耗时0 秒

主表Select All耗时0.015625 秒

连接搜索:100 次
主从表连接搜索耗时:1.4375 秒
平均每条记录耗时:0.014375 秒

===============================
主表记录数:6029615
Count主表耗时0 秒

从表记录数:19925300
Count从表耗时0 秒

主表Select All耗时0 秒

连接搜索:100 次
主从表连接搜索耗时:1.484375 秒
平均每条记录耗时:0.01484375 秒
最后编辑enjoyo 最后编辑于 2008-03-15 12:18:53
Sinoprise Network Studio
        ----专注.NET技术
 

关于改进版的COMB数据库效率的测试(5)

==========================================================
测试完成后的数据库大小:


测试完成后从表的大小:



测试完成后,从表索引的大小:



主表的数据大小是:414M(434,132,280字节),主表索引文件大小:300M(315,144,192字节)。

结论:

用GUID(改良后的)字符串做主键没有想象的效率那么低,但是会造成数据库的大小增加,索引文件的大小增加。在对存储空间要求不是很严格(存储空间不是主要问题的情况下),可以考虑用GUID字符串做主键,但在对空间要求较高的环境下,如嵌入式(WindowsMobile)等,需要综合考虑。在需要多库数据同步的情况下,建议用GUID字符串做主键,这样多库同步会比较简单。
Sinoprise Network Studio
        ----专注.NET技术
 

回复: 关于改进版的COMB数据库效率的测试(1)

K,照片还贴不过来, http://blog.sina.com.cn/kevdmx
Sinoprise Network Studio
        ----专注.NET技术
 
1  /  1  页   1 跳转

版权所有 Sinoprise Network Studio   Sitemap

Powered by Discuz!NT 2.0.1214    Copyright © 2001-2009 Comsenz Inc.
Processed in 0.140625 second(s) , 3 queries. 京ICP备05062328号
返顶部