-
主键只可能有一个,但一个主键可以由多个字段组成
2011-03-19 09:14:00在绿色工具里,可以对多个字段打上主键的标识“锁”,但这并不表示表拥有了多个主键,而是说这几个字段共同构成了主键。当然,他们之间也是有次序的。查看次序可以使用show index from table。会看到Key_Name中有多...在绿色工具里,可以对多个字段打上主键的标识“锁”,但这并不表示表拥有了多个主键,而是说这几个字段共同构成了主键。当然,他们之间也是有次序的。查看次序可以使用show index from table。会看到Key_Name中有多个Primary,而Seq_in_index便是指各字段在主键中的优先顺序,当然了,对多个字段构成的索引也是一样的道理。
-
数据库中使用自增量字段与Guid字段作主键的性能对比
2015-09-15 17:30:241.概述: 在我们的数据库设计中... 自增量字段每次都会按顺序递增,可以保证在一个表里的主键不重复。除非超出了自增字段类型的最大值并从头递增,但这几乎不可能。使用自增量字段来做主键是非常简单的,一般只需1.概述:
在我们的数据库设计中,数据库的主键是必不可少的,主键的设计对整个数据库的设计影响很大.我就对自动增量字段与Guid字段的性能作一下对比,欢迎大家讨论.
2.简介:
1.自增量字段
自增量字段每次都会按顺序递增,可以保证在一个表里的主键不重复。除非超出了自增字段类型的最大值并从头递增,但这几乎不可能。使用自增量字段来做主键是非常简单的,一般只需在建表时声明自增属性即可。
自增量的值都是需要在系统中维护一个全局的数据值,每次插入数据时即对此次值进行增量取值。当在当量产生唯一标识的并发环境中,每次的增量取值都必须最此全局值加锁解锁以保证增量的唯一性。这可能是一个并发的瓶颈,会牵扯一些性能问题。
在数据库迁移或者导入数据的时候自增量字段有可能会出现重复,这无疑是一场恶梦(本人已经深受其害).
如果要搞分布式数据库的话,这自增量字段就有问题了。因为,在分布式数据库中,不同数据库的同名的表可能需要进行同步复制。一个数据库表的自增量值,就很可能与另一数据库相同表的自增量值重复了。
2.uniqueidentifier(Guid)字段
在MS Sql 数据库中可以在建立表结构是指定字段类型为uniqueidentifier,并且其默认值可以使用NewID()来生成唯一的Guid(全局唯一标识 符).使用NewID生成的比较随机,如果是SQL 2005可以使用NewSequentialid()来顺序生成,在此为了兼顾使用SQL 2000使用了NewID().
Guid:指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,其算法是通过以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字生成。其格式为:04755396-9A29-4B8C-A38D-00042C1B9028.
Guid的优点就是生成的id比较唯一,不管是导出数据还是做分步开发都不会出现问题.然而它生成的id比较长,占用的数据库空间也比较多,随着外存价格的下降,这个也无需考虑.另外Guid不便于记忆,在这方面不如自动增量字段,在作调试程序的时候不太方便。
3.测试:
1.测试环境
操作系统:windows server 2003 R2 Enterprise Edition Service Pack 2
数据库:MS SQL 2005
CPU:Intel(R) Pentium(R) 4 CPU 3.40GHz
内存:DDRⅡ 667 1G
硬盘:WD 80G
2.数据库脚本
--自增量字段表
CREATE TABLE [dbo].[Table_Id](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Value] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,
CONSTRAINT [PK_Table_Id] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
--Guid字段表
CREATE TABLE [dbo].[Table_Guid](
[Guid] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Table_Guid_Guid] DEFAULT (newid()),
[Value] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,
CONSTRAINT [PK_Table_Guid] PRIMARY KEY CLUSTERED
(
[Guid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
测试代码
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Data.SqlClient;
5using System.Diagnostics;
6using System.Data;
7
8namespace GuidTest
9{
10class Program
11{
12string Connnection = "server=.;database=GuidTest;Integrated Security=true;";
13static void Main(string[] args)
14{
15Program app = new Program();
16int Count = 10000;
17Console.WriteLine("数据记录数为{0}",Count);
18//自动id增长测试;
19Stopwatch WatchId = new Stopwatch();
20Console.WriteLine("自动增长id测试");
21Console.WriteLine("开始测试");
22WatchId.Start();
23Console.WriteLine("测试中
");
24
25app.Id_InsertTest(Count);
26//app.Id_ReadToTable(Count);
27//app.Id_Count();
28
29//查询第300000条记录;
30//app.Id_SelectById();
31
32WatchId.Stop();
33Console.WriteLine("时间为{0}毫秒",WatchId.ElapsedMilliseconds);
34Console.WriteLine("测试结束");
35
36Console.WriteLine("-----------------------------------------");
37//Guid测试;
38Console.WriteLine("Guid测试");
39Stopwatch WatchGuid = new Stopwatch();
40Console.WriteLine("开始测试");
41WatchGuid.Start();
42Console.WriteLine("测试中
");
43
44app.Guid_InsertTest(Count);
45//app.Guid_ReadToTable(Count);
46//app.Guid_Count();
47
48//查询第300000条记录;
49//app.Guid_SelectById();
50
51WatchGuid.Stop();
52Console.WriteLine("时间为{0}毫秒", WatchGuid.ElapsedMilliseconds);
53Console.WriteLine("测试结束");
54Console.Read();
55}
56
57///
58/// 自动增长id测试
59///
60private void Id_InsertTest(int count)
61{
62string InsertSql="insert into Table_Id ([Value]) values ({0})";
63using (SqlConnection conn = new SqlConnection(Connnection))
64{
65conn.Open();
66SqlCommand com = new SqlCommand();
67for (int i = 0; i < count; i++)
68{
69com.Connection = conn;
70com.CommandText = string.Format(InsertSql, i);
71com.ExecuteNonQuery();
72}
73}
74}
75
76///
77/// 将数据读到Table
78///
79private void Id_ReadToTable(int count)
80{
81string ReadSql = "select top " + count.ToString() + " * from Table_Id";
82using (SqlConnection conn = new SqlConnection(Connnection))
83{
84SqlCommand com = new SqlCommand(ReadSql, conn);
85SqlDataAdapter adapter = new SqlDataAdapter(com);
86DataSet ds = new DataSet();
87adapter.Fill(ds);
88Console.WriteLine("数据记录数为:{0}", ds.Tables[0].Rows.Count);
89}
90}
91
92///
93/// 数据记录行数测试
94///
95private void Id_Count()
96{
97string ReadSql = "select Count(*) from Table_Id";
98using (SqlConnection conn = new SqlConnection(Connnection))
99{
100SqlCommand com = new SqlCommand(ReadSql, conn);
101conn.Open();
102object CountResult = com.ExecuteScalar();
103conn.Close();
104Console.WriteLine("数据记录数为:{0}",CountResult);
105}
106}
107
108///
109/// 根据id查询;
110///
111private void Id_SelectById()
112{
113string ReadSql = "select * from Table_Id where Id="+300000;
114using (SqlConnection conn = new SqlConnection(Connnection))
115{
116SqlCommand com = new SqlCommand(ReadSql, conn);
117conn.Open();
118object IdResult = com.ExecuteScalar();
119Console.WriteLine("Id为{0}", IdResult);
120conn.Close();
121}
122}
123
124///
125/// Guid测试;
126///
127private void Guid_InsertTest(int count)
128{
129string InsertSql = "insert into Table_Guid ([Value]) values ({0})";
130using (SqlConnection conn = new SqlConnection(Connnection))
131{
132conn.Open();
133SqlCommand com = new SqlCommand();
134for (int i = 0; i < count; i++)
135{
136com.Connection = conn;
137com.CommandText = string.Format(InsertSql, i);
138com.ExecuteNonQuery();
139}
140}
141}
142
143///
144/// Guid格式将数据库读到Table
145///
146private void Guid_ReadToTable(int count)
147{
148string ReadSql = "select top "+count.ToString()+" * from Table_GuID";
149using (SqlConnection conn = new SqlConnection(Connnection))
150{
151SqlCommand com = new SqlCommand(ReadSql, conn);
152SqlDataAdapter adapter = new SqlDataAdapter(com);
153DataSet ds = new DataSet();
154adapter.Fill(ds);
155Console.WriteLine("数据记录为:{0}", ds.Tables[0].Rows.Count);
156}
157}
158
159///
160/// 数据记录行数测试
161///
162private void Guid_Count()
163{
164string ReadSql = "select Count(*) from Table_Guid";
165using (SqlConnection conn = new SqlConnection(Connnection))
166{
167SqlCommand com = new SqlCommand(ReadSql, conn);
168conn.Open();
169object CountResult = com.ExecuteScalar();
170conn.Close();
171Console.WriteLine("数据记录为:{0}", CountResult);
172}
173}
174
175///
176/// 根据Guid查询;
177///
178private void Guid_SelectById()
179{
180string ReadSql = "select * from Table_Guid where Guid='C1763624-036D-4DB9-A1E4-7E16318C30DE'";
181using (SqlConnection conn = new SqlConnection(Connnection))
182{
183SqlCommand com = new SqlCommand(ReadSql, conn);
184conn.Open();
185object IdResult = com.ExecuteScalar();
186Console.WriteLine("Guid为{0}", IdResult);
187conn.Close();
188}
189}
190}
191
192}
1933.数据库的插入测试
测试1
数据库量为:100条
运行结果
测试2
数据库量为:10000条
运行结果
测试3数据库量为:100000条
运行结果
测试4
数据库量为:500000条
运行结果
4.将数据读到DataSet中
测试1
读取数据量:100
运行结果
测试2
读取数据量:10000
运行结果
测试3
读取数据量:100000
运行结果
测试4
读取数据量:500000
运行结果
4.记录总数测试
测试结果
5.指定条件查询测试
查询数据库中第300000条记录,数量记录量为610300.
4.总结:
使用Guid作主键速度并不是很慢,它反而要比使用自动增长型的增量速度还要快.
5.参考:
http://www.cnblogs.com
http://www.cnblogs.com/leadzen/archive/2008/05/10/1191010.html
5.2.2 选择主键
主键是能够惟一地定义一行数据的一列或多列。主键中的列值不能设置为null值。主键为数据库引擎提供了一种获取数据库表中某个特定行的方法。主键还用于保证引用的完整性。在处理非连接数据时,如果多个用户同时插入数据,则必须确保不会出现重复的主键。
1. 对比智能键、常规键和代理键
智能键是一种基于商业数据表示的键。例如,SKU(Stock Keeping Unit,常用保存单元)就是智能键的一个例子,它定义为一个包含10个字符的字段(在数据库中定义为CHAR(10))。该SKU可能包含以下信息:前四个字符保存供应商代号,随后的三个字符保存产品类型代号,最后三个字符保存一个序列号。
常规键(natural primary key)由商业数据中现有的单个或多个列构成,用于惟一地标识记录。例如,某个现有的商业过程可能要使用社会保险号来标识医院的患者。
尽管智能键和常规键互不相同,但它们都由使用商业相关数据的列构成,并且用户一般都可以查看它们。本书以后将这些键统一称为智能键。
代理主键的键值是由系统生成的,这些值与行中的商业数据没有关系,因此又称为非智能键(dumb key)。本书以后将这些键统一称为代理键(surrogate key)。自动增值的列就是这种键的一个例子,在添加新的行时,该列的值将相应地设置为1,2,3…,依此类推。在Microsoft SQL Server中,自动增值的列称为Identity列。本书以后将这种键统一称为Identity键(identity key)。GUID(globally unique identifier,全局惟一标识符)是另一个由系统生成键值的例子,它通过使用取值算法来生成惟一的键值。本书以后将这种键统一称为GUID键。
专家推荐使用哪一种主键类型呢?不同的专家有着各自的见解。大家在做出选择之前,应深入地理解各种方法的主要优缺点。
图5.3显示了智能键和代理键的一种实现示例。该示例包含三个表:第一个表用于保存作者数据,第二个表用于保存书籍数据,第三个表是一个多对多的联接表(join table),因为一个作者能够编写多本书籍,一本书籍也能够由多个作者共同编写。
注意,代理主键的实现在TblAuthor和TblBook表中额外包含了一个Id列,因为代理主键的键值是由系统生成的,与行数据无关。用户应不能看见代理主键。下面,我们将分析智能键与代理主键之间在实现上的差异。
数据大小 数据大小本身并不十分重要,重要的是在数据库和客户之间传输数据时所占用的带宽。代理主键的实现在每个主表中都额外增加了一列。这将显著地增大数据量的大小。如果代理主键是一个GUID列,则增加的列将使每行增加16个字节。如果增加的是一个自动增值的列,则因该列引起的数据增量取决于所选用的数据类型(int型增加4个字节,long型增加8个字节)。由于联接表通常包含数量庞大的行记录,因此在分析数据库大小的总体差异时,一定要考虑到智能键与代理主键在数据增量大小方面的差异。此外,主键通过创建一个惟一索引来确保自身的惟一性,因此还要考虑到这方面的数据增量。表5.1列出了每种主键类型在数据增量方面的比较结果。
智能键 代理键
图5.3 智能键和代理键的实现示例
表5.1 主键大小示例
描述
智能键
Identity键(int型)
GUID键
1000条作者记录
9个字节/SSN = 9,000个字节
4个字节/int = 4,000个字节
16个字节/GUID = 16,000个字节
3000条书籍记录
10个字节/ISBN = 30,000个字节
4个字节/int = 12,000个字节
16个字节/GUID = 48,000个字节
10,000条作者/书籍记录
19个字节/键= 190,000个字节
8个字节/键 = 80,000个字节
32个字节/键 = 320,000个字节
小计
229,000个字节
96,000个字节
384,000个字节
索引
229,000个字节
96,000个字节 + 9000个SSN + 30,000个ISBN = 135,000个字节
384,000个字节 + 9000个SSN + 30,000个ISBN = 423,000个字节
总数
458,000个字节
231,000个字节
807,000个字节
显然,Identity键是这一比较回合的赢家,但要记住的是,int型的最大值是231-1=2 147 483 647。对于大多数应用程序而言,该值已经足够了,但是有些应用程序需要使用long数据类型来保存更多的记录。注意,计算不同类型索引大小的方法是互不相同的。代理键的实现仍需要在SSN列和ISBN列上提供一个惟一索引,以确保这些列的惟一性。
键的可见性 代理键对用户是不可见的,但智能键是可见的,并且用户知道如何使用智能键。客户应用程序可以隐藏代理键,但数据库工具却不能隐藏它们。这就要求使用数据库工具的人员必须理解如何使用代理键。因此,智能键是这一比较回合的赢家。
键的易修改性 主键是难以进行修改的,因为如果对主键进行修改,则修改结果必然对子表造成影响。这时就应该使用代理键取代智能键。为什么呢?因为代理键并不显示给用户,所以不必修改它们;而智能键包含用户可以看到的商业数据,因此必须允许该数据能够进行修改。
int型代理键也需要进行修改,以确保惟一性(正如前文所述),但GUID型代理键从不需要进行修改。这正是我为什么喜欢使用GUID型代理键的主要原因。
联接个数 在某些情况中,可以使用智能键来减少联接的个数。例如,如果想运行一个显示每个作者所著书籍的报表,并且该报表只包含作者的SSN字段和书籍的ISBN字段,则在实现智能主键时,只需查询TblAuthorBook联接表即可。在实现代理主键时,必须联合查询TblAuthor表、TblAuthorBook表和TblBook表才能获得该信息。因此,智能键是这一比较回合的赢家,但实践中很少只查询这两列信息而不查询其他的信息,诸如作者的姓名和书名。
SQL复杂性 智能键的实现通常使用多个列来确保惟一性。SQL查询会因为使用这样的复合智能键而变得错综复杂。正如前文所述,尽管可以联合更多的代理键,但代理键更易于使用,因为它们不使用复合键(联接表除外)。对比前面两种代理键类型,Identity键在实现上比GUID键更易于编写查询,但是一旦掌握了GUID数据类型(稍后将会予以讨论)的使用特点,就会发现,GUID键相较于Identity键,并不是特别难用的。
在非连接时确保惟一性 在 非连接环境中,几乎不能保证智能键在用户输入数据时的惟一性。问题是在向数据库服务器添加新行时,有人可能输入匹配信息,从而导致冲突。有人可能会辩解 说,使用代理键就可以解决该问题,但不要忘记,大家仍可以在诸如社会保险号或车辆标识号等字段上创建惟一索引,以在添加重复信息时能抛出一个异常。
在使用int型代理键时,管理主键列编号的窍门是将DataSet非连接对象中的AutoIncrement属性设置为true,AutoIncrementStep(增量)设置为-1(负1),AutoIncrementSeed(起始值)设置为-1,这样,在添加新行时,编号将从-1开始,每新增一行,编号就减1。负值认为是非连接占位符,因此不会与服务器的Identity列设置产生冲突,因为服务器只会分配正值编号。下面的SQL命令首先插入一行数据,然后立即查询该插入行。该命令所返回的信息用于将占位符(负值键)更新为数据库所创建的值。
SQL INSERT命令
INSERT INTO [TBLAUTHOR] ([SSN], [LastName], [FirstName])
VALUES (@SSN, @LastName, @FirstName)
SELECT Id, SSN, LastName, FirstName FROM TblAuthor
WHERE (Id = SCOPE_IDENTITY())
SCOPE_IDENTITY函数返回刚才所插入的作者ID值。注意,不要使用@@IDENTITY函数,因为在激活一个插入触发器,以在包含Identity列的表中插入一行或多行数据时,该函数将返回一个错误值。
因为必须获取服务器中的 数据来更新非连接数据中的占位符,所以必须考虑更新主键值对性能的影响。如果使用服务器中创建的值更新非连接数据键,会发生什么情况呢?这时,所有的子数 据都必须进行更新,以反映键值的变化;为实现这一目的,可以根据它们之间的相互关系启用级联更新功能。这又会引出另一个性能问题,尤其对于较大的DataSet对象。
在使用GUID代理主键时,一旦设置了主键就不必再修改它。主要的问题是如何设置键值。下面的代码片段演示了如何初始化GUID。
Visual Basic
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
For Each dt As DataTable In salesSurrogateGuidKeyDs.Tables
If (not dt.Columns("Id") Is Nothing) Then
AddHandler dt.TableNewRow, addressof InitializeGuid
End If
Next
End Sub
Private Sub InitializeGuid(ByVal sender As Object, _
ByVal e As DataTableNewRowEventArgs)
If (TypeOf e.Row("Id") Is DBNull) Then
e.Row("Id") = Guid.NewGuid()
End If
End Sub
C#
public Form1() //constructor
{
InitializeComponent();
foreach (DataTable dt in sales_SurrogateGuidKeyDs.Tables)
{
if(dt.Columns["Id"] != null)
dt.TableNewRow += new DataTableNewRowEventHandler(InitializeGuid);
}
}
private void InitializeGuid(object sender, DataTableNewRowEventArgs e)
{
if(e.Row["Id"] is DBNull)
e.Row["Id"] = Guid.NewGuid();
}
因为TblAuthor表和TblBook表具有同名的主键(“Id”),所以前面的示例代码包含一个InitializeGuid方法,用于创建新的GUID,在触发这些表的TableNewRow事件时,将调用该方法。通常,像该示例代码那样,使所有的代理键具有相同的名称是一种不错的做法。不必使用该实现创建级联关系。所以,GUID型代理键是这一比较回合的赢家。
在数据库间移动数据 在实现Identity键时,需要额外做一些工作才能在数据库之间移动数据。假设表的键值范围从1到n,这些值也可以作为数据库中所有外键的值。如何取出该数据,并将其合并到另一个使用相同数据编号的数据库中呢?要想解决这一问题,则需要对所有的Identity列进行重新编号。
如果使用GUID键实现,则移动数据只是将数据从一个数据库复制到另一个数据库,因此,GUID键是这一比较回合的赢家。
最终的赢家是… 我刚刚开发完成了一项实现GUID键的大型项目,并且还开发了多个使用智能键和Identity键实现的项目。表5.2总结了各种键类型在一些影响性能、数据大小和易用性等因素中所占的百分比。我根据自己使用这些键类型的经验,将权重值的范围设定为0%到100%,其中100%表示权重值最大。此外,键类型的系数分为以下三级:第一级系数为1,第二级系数为0.5,第三级系数为0,通过将键类型系数乘以每个因素的权重值,就可以得到每种键类型的权重值。
表5.2 基于因素及其权重的最终百分比
权重值
因素及其权重
智能键
Identity键
GUID键
数据大小 = 25%
12.5%
25%
0%
键的可见性 = 5%
5%
2.5%
0%
键的易修改性 = 20%
0%
10%
20%
联接个数 = 5%
5%
2.5%
2.5%
SQL复杂性 = 5%
0%
5%
2.5%
确保惟一性 = 25%
0%
12.5%
25%
数据移动 = 15%
7.5%
0%
15%
总计 = 100%
30%
57.5%
65%
根据表5.2中的权重值,GUID键的绝大部分因素权重值都是最大的。如果大家对某些因素的权重存有异议,可以尝试着修改权重以验证是否能得到不同的结果。注意,这些主键的实现都不能面分之百地满足所有因素。一般认为,GUID键实现是最适合非连接数据应用程序的。智能键实现是否有属于自己的用武之地呢?有的,它最适合用于数据仓库应用程序,因为数据仓库应用程序在设计上一般都会提供高性能只读访问,并且包含最少的联接数。因为数据是只读的,所以“修改键”因素所占的权重较小。表5.3通过对表5.2中的权重进行局部调整,提供了各种键类型基于另一种权重的百分比。
表5.3 基于因素及其权重的数据仓库百分比
权重值
因素及其权重
智能键
Identity键
GUID键
数据大小=25%
12.5%
25%
0%
键的可见性=10%
10%
0%
0%
键的易修改性=5%
0%
2.5%
5%
联接个数=25%
25%
0%
0%
SQL复杂性=10%
10%
5%
5%
确保惟一性=5%
0%
0%
5%
数据移动=20%
10%
0%
20%
总计=100%
67.5%
32.5%
35%
前面的表只是作为一种参考,大家在做项目的时候,一定要考虑到其他可能影响项目的任何因素。
5.3 GUID的用法
许多开发人员在试图使用GUID键时,对GUID感到非常恐惧。GUID可能非常大,但它们并不难以使用。下面将介绍一些使用技巧。
5.3.1 复制/粘贴GUID
在调试时,可以选中包含一个GUID键的代码,这时IntelliSense会显示该GUID键(如图5.4所示);接着,选中该GUID键的键值,并将其复制到剪贴板;然后将该值粘贴到一个查询窗口中,并将大括号替换为单引号,如下面的SQL语句所示。
图5.4 使用IntelliSense复制一个GUID键,并将其粘贴到查询工具中
使用GUID键的SQL查询命令
SELECT Id, SSN, LastName, FirstName
FROM TblAuthor
WHERE (Id = 'cbc8c64c-6ba6-4bec-baef-4c0e50e8b251')
5.3.2 在非联接表中使用同名的主键列
强烈建议大家在所有非联接表中使用同名的主键列(诸如Id)。这样做有利于编写处理GUID键的存储过程。此外,使主键成为每个表中的第一列还可以帮助用户理解该字段的目的。
5.3.3 查找数据库中的GUID
由于数据库的设计原因,大家在查找某个外键列中的一个GUID时,却不知道该GUID的数据在哪儿。例如,假设有一个如图5.5所示的独占性OR关系。这种类型的关系经常出现在面向对象的环境中——一个Book类可能包含多个子类,诸如Ebook类、PaperBack类和HardCover类。这些类的字段互不相同,因此要么创建一个包含大量列值为null的表,要么如图5.5所示,为每个子类单独创建一个表,必须在这两种方法中选择其一。
图5.5 独占性OR关系的一个示例
如果想确定某个特定的GUID包含在哪个表中,则可以使用下面的存储过程来定位将该GUID作为主键值的表。
SQL uspGetDataForId
CREATE PROCEDURE dbo.uspGetDataForId
(
@id uniqueidentifier
)
AS
SET NOCOUNT ON
--NOTE: This proc assumes that all user tables have 'Tbl' prefix
--Usage: in Query Analyser, type the following without the '--'
--exec uspGetDataForId '78257ec8-c8f9-4d35-a636-d58d8a67c3d4'
DECLARE @tbl varchar(2000)
DECLARE @sql varchar(2000)
IF OBJECT_ID('tempdb..#idTable') IS NOT NULL DROP TABLE #idTable
CREATE TABLE #idTable (
Id uniqueidentifier,
Count INT,
TableName varchar(2000)
)
DECLARE tables_cursor CURSOR
FOR SELECT TABLE_NAME FROM information_schema.Tables
WHERE substring (TABLE_NAME,1,3)='Tbl'
OPEN tables_cursor
FETCH NEXT FROM tables_cursor INTO @tbl
WHILE @@FETCH_STATUS = 0
BEGIN
IF EXISTS (SELECT * FROM information_schema.columns
WHERE table_name=@tbl AND Column_Name='Id')
BEGIN
SET @sql = 'INSERT INTO #idTable SELECT id as ''Id'', '
+ 'count(*) as ''Count'',''' + @tbl +''' as ''TableName'' FROM '
+ @tbl + ' WHERE ID=''' + CONVERT(varchar(2000),@id)
+ ''' group by Id'
EXEC(@sql)
END
FETCH NEXT FROM tables_cursor INTO @tbl
END
CLOSE tables_cursor
DEALLOCATE tables_cursor
SELECT Id, TableName FROM #idTable WHERE Count > 0
注意,该存储过程要求所有主键列的名称都为Id,用户表的前缀都为Tbl。该存储过程没有尝试在其他任何列中查找一个GUID,但如果需要查找所有使用某个GUID的位置,则要读取所有的列。
-
数据库中使用自增量字段与Guid字段主键的性能对比
2010-07-05 10:03:00自增量字段 自增量字段每次都会按顺序递增,可以保证在一个表里的主键不重复。除非超出了自增字段类型的最大值并从头递增,但这几乎不可能。使用自增量字段来做主键是非常简单的,一般只需在建表时声明自增...1.概述:
在我们的数据库设计中,数据库的主键是必不可少的,主键的设计对整个数据库的设计影响很大.我就对自动增量字段与Guid字段的性能作一下对比,欢迎大家讨论.
2.简介:
1.自增量字段
自增量字段每次都会按顺序递增,可以保证在一个表里的主键不重复。除非超出了自增字段类型的最大值并从头递增,但这几乎不可能。使用自增量字段来做主键是非常简单的,一般只需在建表时声明自增属性即可。
自增量的值都是需要在系统中维护一个全局的数据值,每次插入数据时即对此次值进行增量取值。当在当量产生唯一标识的并发环境中,每次的增量取值都必须最此全局值加锁解锁以保证增量的唯一性。这可能是一个并发的瓶颈,会牵扯一些性能问题。
在数据库迁移或者导入数据的时候自增量字段有可能会出现重复,这无疑是一场恶梦(本人已经深受其害).
如果要搞分布式数据库的话,这自增量字段就有问题了。因为,在分布式数据库中,不同数据库的同名的表可能需要进行同步复制。一个数据库表的自增量值,就很可能与另一数据库相同表的自增量值重复了。
2.uniqueidentifier(Guid)字段
在MS Sql 数据库中可以在建立表结构是指定字段类型为uniqueidentifier,并且其默认值可以使用NewID()来生成唯一的Guid(全局唯一标识符).使用NewID生成的比较随机,如果是SQL 2005可以使用NewSequentialid()来顺序生成,在此为了兼顾使用SQL 2000使用了NewID().
Guid:指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,其算法是通过以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字生成。其格式为:04755396-9A29-4B8C-A38D-00042C1B9028.
Guid的优点就是生成的id比较唯一,不管是导出数据还是做分步开发都不会出现问题.然而它生成的id比较长,占用的数据库空间也比较多,随着外存价格的下降,这个也无需考虑.另外Guid不便于记忆,在这方面不如自动增量字段,在作调试程序的时候不太方便。
3.测试:
1.测试环境
操作系统:windows server 2003 R2 Enterprise Edition Service Pack 2
数据库:MS SQL 2005
CPU:Intel(R) Pentium(R) 4 CPU 3.40GHz
内存:DDRⅡ 667 1G
硬盘:WD 80G
2.数据库脚本
--自增量字段表
CREATE TABLE [dbo].[Table_Id](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Value] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,
CONSTRAINT [PK_Table_Id] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
--Guid字段表
CREATE TABLE [dbo].[Table_Guid](
[Guid] [
-
据库中使用自增量字段与Guid字段主键的性能对比
2009-07-29 14:34:00自增量字段 自增量字段每次都会按顺序递增,可以保证在一个表里的主键不重复。除非超出了自增字段类型的最大值并从头递增,但这几乎不可能。使用自增量字段来做主键是非常简单的,一般只需在建表时声明自增属性即可...2.简介:
1.自增量字段
自增量字段每次都会按顺序递增,可以保证在一个表里的主键不重复。除非超出了自增字段类型的最大值并从头递增,但这几乎不可能。使用自增量字段来做主键是非常简单的,一般只需在建表时声明自增属性即可。
自增量的值都是需要在系统中维护一个全局的数据值,每次插入数据时即对此次值进行增量取值。当在当量产生唯一标识的并发环境中,每次的增量取值都必须最此全局值加锁解锁以保证增量的唯一性。这可能是一个并发的瓶颈,会牵扯一些性能问题。
在数据库迁移或者导入数据的时候自增量字段有可能会出现重复,这无疑是一场恶梦(本人已经深受其害).
如果要搞分布式数据库的话,这自增量字段就有问题了。因为,在分布式数据库中,不同数据库的同名的表可能需要进行同步复制。一个数据库表的自增量值,就很可能与另一数据库相同表的自增量值重复了。
2.uniqueidentifier(Guid)字段
在MS Sql 数据库中可以在建立表结构是指定字段类型为uniqueidentifier,并且其默认值可以使用NewID()来生成唯一的Guid(全局唯一标识符).使用NewID生成的比较随机,如果是SQL 2005可以使用NewSequentialid()来顺序生成,在此为了兼顾使用SQL 2000使用了NewID().
Guid:指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,其算法是通过以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字生成。其格式为:04755396-9A29-4B8C-A38D-00042C1B9028.
Guid的优点就是生成的id比较唯一,不管是导出数据还是做分步开发都不会出现问题.然而它生成的id比较长,占用的数据库空间也比较多,随着外存价格的下降,这个也无需考虑.另外Guid不便于记忆,在这方面不如自动增量字段,在作调试程序的时候不太方便。
转(http://www.cnblogs.com/houleixx/archive/2008/12/13/Id_And_Guid.html)
-
access在哪里可以设主键_access设置主键
2021-01-17 18:34:02所谓的主键,其实并非大家想象中的那么神秘,主键其实也是一个字段而已,只不过,该字段中的任何数据,都是唯一的,没有任何两个数据相同,这就好比我们的身份证号码一样,没有任何两个人的身份证号码相同。... -
自增量字段与GUID字段作为主键的区别
2012-08-29 23:17:41自增量字段每次都会按顺序递增,可以保证在一个表里的主键不重复。使用也比较简单,只需在建表时声明为自增属性即可。 自增量的值是需要在系统中维护一个全局的数据值,每次插入数据时即对此值进行增量取值。当在... -
oracle表中指定字段自增
2020-05-26 15:28:06表里指定字段自增,这个问题在SQLSERVER里面来说很简单 ,Identity(1,1)该字段就会从1开始,按照+1的方式自增. 但是在Oracle里面呢,就需要用到序列和触发器完成才可以...表中主键列是F_ID ,接下来就指定该列F_ID自增长 -
可能只需要花费你一分钟就能掌握的 Mysql 主键约束!
2018-12-28 19:31:48今天来介绍两种Mysql中的主键约束。 一、主键定义 键是表的标识列,关系数据库依赖于主键,它...在创建表的同时设置主键,可以放在单字段后,也可以放在表的末尾 alter table 表名 modify 字段名 字段类型 primar... -
Sql server中的主键与外键
2012-08-04 09:37:07在一个表中只能设置一个主键约束,但可以将包含多个字段的字段组合设置为主键。主键约束分为字段级约束和表级约束。字段级约束是为某一个字段设置约束。在设置字段级约束时,只需将创建主键约束的语句添加到该字段的... -
Django学习-第七讲:django 中的常用字段、字段属性,外键和表关系、外键操作
2020-10-13 20:47:06如果你想指定一个其他名字的并且具有自动增长的主键,使用AutoField也是可以的。 2. BigAutoField 64位的整形,类似于AutoField,只不过是产生的数据的范围是从1-9223372036854775807。 3. BooleanField 在模型层面... -
mysql主键自增长_MySQL表自增id用完了该怎么办?
2020-12-05 12:21:00我们知道MySQL表可以定义一个自增长的id,如果我们的表没有指定主键字段,那MySQL会给我们的表创建一个不可见的,长度为6个自己的row_id,然后不停地往上加步长,虽然生活中自然数是没有上限的,但是在计算机里,... -
自动增长字段
2018-10-22 02:34:00在设计数据库的时候,有时需要表的某个字段是自动增长的,最常使用...MYSQL中设定一个字段为自动增长字段非常简单,只要在表定义中指定字段为AUTO_INCREMENT即可。比如下面的SQL语句创建T_Person表,其中主键FId为自... -
mysql 两个字段拼接_数据分析mysql入门到精通(3)
2021-01-05 05:30:351,高级数据操作2,查询数据3,查询中的运算符4,联合查询5,连接查询6,交叉查询7,内连接8.外连接9,using关键字高级数据操作新增数据多...主键冲突 主键冲突:在有的表中,使用的是业务主键(字段有业务含义),... -
关于数据库中一对多关系的表的设计问题
2017-02-09 04:00:57很简单,现有一张商品表(goods),里面有3个字段(id自增主键,name商品名字,price价格); 现在准备设计一张订单表(order),要求一张订单可能包含一个或多个商品,而且商品数量不定,那么应该如何设计这个订单... -
mysql字段约束
2016-04-11 11:04:00主键是表的标志列,在mysql中支持将一个或多个字段作为一个主键来使用。关系数据库依赖于主键,主键在物理层面只有两个用途: 唯一的标志一行记录 作为一个可以被外键引用的有效对象。 2>设置主键: 创建主键分为... -
主键和唯一索引的区别
2019-04-24 17:48:09主键: 是约束 ... 是在一个字段上建立 一张表可以有多个唯一索引 不能作为外键 索引是物理上存在的 mysql/sqlserver/oracle 中, 主键和唯一约束都会被自动添加唯一索引 参考: https://www.cnblogs.com/... -
C#,请问怎么在一个form上显示报表
2010-12-03 21:37:00似水晶报表的东西在xtrareport中没找到啊,烦躁 这样的就不行,因为只找ID 在两表中是不有相同或不同,如名字不同就找不出. 还有就是如果有一个表多一个记录,也算是两个表有不同记录 没有主键,... -
主键与索引
2009-10-15 18:00:00区别:1:主键是为了标识数据库记录唯一性,不允许记录重复,且键值不能为空,主键也是一个特殊索引.2:数据表中只允许有一个主键,但是可以有多个索引.3.使用主键会数据库会自动创建主索引,也可以在非主键上创建索引,方便... -
主键和索引区别
2008-05-27 23:19:39主键和索引是两个概念 但当你建主键的时候,数据库会自动帮你建上索引 ...从数据库的应用来说, 每个表只可以有最多一个主键, 而表中其他的字段皆可以 用这个键为代表, 例如学生的注册纪录中,... -
MySQL InnoDB引擎,主键自增的实用性高吗? 主键自增的优点和缺点如何取舍?
2019-09-26 12:02:53如果从数据库索引优化角度看,使用InnoDB引擎而不使用自增主键绝对是一个糟糕的主意。 InnoDB使用聚集索引,数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存... -
MySQL | 删除表中重复数据
2019-01-31 10:11:24t_api_info 表,id为主键,自增字段,parent_id 是表中相同字段(可以多个也可以选关键得几个,排序可要可不要) 实现:从t_api_info表中去重根据parent_id字段,只留下每组id最大得那一条记录 DELETE FROM t_... -
[笔记]流行数据库SQL差异分析之“自动增长字段”
2019-10-09 04:16:33自动增长字段 在设计数据库的时候,有时需要表的某个字段...MYSQL中设定一个字段为自动增长字段非常简单,只要在表定义中折定字段为AUTO_INCREMENT即可。比如下面的SQL语句创建Person表,其中主键Fid为自动 增长字... -
MySQL不建议使用UUID作为主键的原因
2020-12-01 22:04:25mysql在innodb的存储引擎下是使用B+树来做为索引的数据结构的,而一个表最终必定会创建一个主键索引,即是没有设置主键也会有生成规则(先查找有没有非空的唯一索引,没有则可以使用默认的rowid字段创建索引) ... -
程序员的SQL经典笔记1_自动增长字段
2015-08-14 15:17:47自动增长字段在设计数据库的时候,有时需要表的某个字段是自动增长的,最常使用自动...MYSQL 中设定一个字段为自动增长字段非常简单,只要在表定义中指定字段为AUTO_INCREMENT即可.例子:createtablet_student ( t_idin... -
MySQL添加数据时生成很长串的随机数主键id
2019-05-08 22:39:30前言 主要使用到的技术:...可以向数据库中增加数据,但是主键id是一个长串的随机数。 二、问题分析 新创建一个数据库表,然后手动在数据库表中添加数据时,字段的id值是正常的。但是只要一经过mybatisPlus操... -
Oracle数据库实现字段自增
2013-01-02 20:26:35在用Oracle时,出现了这样一个状况,添加模块时,只传入了一个模块名称,而表中还有一个模块ID,这个ID设定的是自增。但是在Oracle中没有字段自增这个功能。但是可以通过自己写序列、触发器来实现这样的一个功能。... -
设计表三范式
2016-11-14 07:51:34数据库设计三范式(nomorlization) 1NF:原子性,即每个字段都不可以在分割了...3NF:一个表中不能包含其他表中已经存在的非主键字段信息,也就是说只可以包含其他表的主键信息,这样就是主外键,通过主外键就可以进行表 -
数据库学习:表关系
2020-10-30 15:03:26一、关系表 两张表格,一张表的主键作为另一张表的外键,将两张表相互关联,利用外键可以查询到主键所在表的信息。...在一个表中,定义一个字段,这个字段中存储的数据时另外一张表中的主键 就是在 -
最浅显易懂的Django系列教程(17)-模型常用字段
2020-05-14 13:59:30在Django中,定义了一些Field来与数据库表中的字段类型来进行映射。以下将介绍那些常用的字段类型。 AutoField: 映射到数据库中是int类型,可以有自动增长的特性。一般不需要使用这个类型,如果不指定主键,那么...
-
使用 Linux 平台充当 Router 路由器
-
java 四舍五入 0.5_恶心的0.5四舍五入问题
-
2021年 系统分析师 系列课
-
《轴流泵和斜流泵》关醒凡.rar
-
C++代码规范和Doxygen根据注释自动生成手册
-
java正则表达式 匹配()_java正则表达式匹配
-
java正则表达式对象_.Java 使用正则表达式对象实现正则的获取功能
-
车牌检测数据集
-
SPFD5420A.pdf
-
【Python-随到随学】FLask第二周
-
MySQL 多实例安装 及配置主从复制实验环境
-
TL1771S_V0.2_20060508.pdf
-
MySQL 高可用(DRBD + heartbeat)
-
java正则表达式所有字符串_如何在Java中使用正则表达式打印字符串的所有字符?...
-
java正则表达式 提取img_正则表达式提取img的src
-
MySQL 高可用工具 DRBD 实战部署详解
-
鸿蒙系统Harmonyos源码架构分析-第1期第2课
-
MySQL 触发器
-
HSD015E4N2-A Product information V1.3_20050526.pdf
-
深究字符编码的奥秘,与乱码说再见