主键建在什么字段上最好?建在什么字段上最有效率??                         高分求解100总是感到自己建的主键没有起到作用,不得设置主键的关键,所以特别半夜发贴,希望高手解答,谢谢

解决方案 »

  1.   

    你谈到的效率
    用索引
    看下下面的试试全文索引create   table   testIndex 

              id   int   identity(1,1)   primary   key, 
              nm   varchar(100)   unique   not   null, 
              sex   varchar(10) 

    create UNIQUE index UQ__testIndex__0DAF0CB0
    on testindex(nm)insert   into   testindex   
              select   'aaabbb','m'   union   all 
              select   'bbb','w'   union   all 
              select   'ccc','w'   union   all 
              select   'ddd','m' 
    insert   into   testindex   
              select   '麦蒂未伤愈中途退出训练复出时间再度成疑','北京'  
    go
    --创建全文目录 
    sp_fulltext_catalog   'abc','create'     
    go
    --创建全文索引(‘表名‘,’创建/删除‘,’全文目录名‘,’约束名‘) 
    sp_fulltext_table   'testindex','create','abc','UQ__testIndex__0DAF0CB0' 
    go
    --添加列到全文索引(‘表名‘,’列名‘,’添加/删除‘) 
    sp_fulltext_column   'testindex','nm','add' go
    --建立全文索引
    --activate,是激活表的全文检索能力,也就是在全文目录中注册该表
    execute sp_fulltext_table 'testindex','activate'
    go
    --填充全文索引目录
    execute sp_fulltext_catalog 'abc','start_full'
    go--检查全文目录填充情况
    While fulltextcatalogproperty('abc','populateStatus')<>0
    begin--如果全文目录正处于填充状态,则等待30秒后再检测一次
    waitfor delay '0:0:30'
    end--全文目录填充完成后,即可使用全文目录检索
    SELECT   *   FROM   testindex   WHERE   CONTAINS(nm,   '麦蒂') /*id          nm                                                                                                 sex        
    ----------- --------------------------------------------- ------------------------------------------------ ---------- 
    5           麦蒂未伤愈中途退出训练复出时间再度成疑                                                             北京(所影响的行数为 1 行)
    */
    insert   into   testindex   
              select   '麦蒂未伤愈中途退出训练复出时间再度成疑12121','北京'  
    go
    SELECT   *   FROM   testindex   WHERE   CONTAINS(nm,   '麦蒂')
    -----No result
    /*id          nm                                                                                                 sex        
    ----------- --------------------------------------------- ------------------------------------------------ ---------- 
    5           麦蒂未伤愈中途退出训练复出时间再度成疑                                                             北京(所影响的行数为 1 行)
    */
    go--填充全文索引目录
    execute sp_fulltext_catalog 'abc','start_full'
    go
    --检查全文目录填充情况
    While fulltextcatalogproperty('abc','populateStatus')<>0
    begin--如果全文目录正处于填充状态,则等待30秒后再检测一次
    waitfor delay '0:0:30'
    end
    SELECT   *   FROM   testindex   WHERE   CONTAINS(nm,   '麦蒂')go
    /*id          nm                                                                                                   sex        
    ----------- ---------------------------------------------------------------------------------------------------- ---------- 
    6           麦蒂未伤愈中途退出训练复出时间再度成疑12121                                                                             北京
    5           麦蒂未伤愈中途退出训练复出时间再度成疑                                                                                  北京(所影响的行数为 2 行)*/
    sp_fulltext_table  'testindex','drop'
    go
    sp_fulltext_catalog   'abc','drop'  
    go  
    drop table testIndex
      

  2.   

    在看下
    这个偶看 Z老大的书
    做的笔记
    --索引是对是数据库表中一个或多个列的值进行排序的结构
    /*
    (1)聚集索引
       聚集索引基于数据行的键值在表内排序和存储这些数据
       只有当表包含聚集索引时,表中的数据行才按排序顺序存储.如果表具有聚集索引,则该表称为聚集表,每个表只能有一个聚集索引,因为数据行只能按照一个顺序存储
    (2)非聚集索引
       非聚集索引独立存储非聚集索引包含非聚集索引键值并且该键值项都指向该键值的数据行的指针
       从非聚集索引中的索引行指向数据行的指针称为行定位器,行定位器的结构取决与数据页是存储在堆中还是在聚集表中,对于堆,行定位器是指向行的指针.对于聚集表,行定位器是聚集索引键,允许为表建立多个非聚集索引
    (3)索引的存储与检索
      SQL Server以页为数据存储的基本单位,每个夜页的大小为8KB,每页的开始部分是96字节的页首.
     聚集索引和非聚集索引的在B数结构上的差异主要在于B数的叶节点:
       对应聚集索引而言,它是与表中的数据行在一起的,而对于非聚集索引,索引数据是单独存放的,它的叶节点是索引行数据
    (4)索引的检索(5)统计
     在建立索引的时候,SQL会自动的为索引定义中的第一个列创建统计
     当数据库的auto_create_statistics设置为ON时,SQL查询优化器会根据查询条件在相关的列上自动建立统计
      create statistics语句手工创建统计
      通过表或索引视图已提供列或一组列创建组状图和关联密度组
    */
    --统计的重要性
    alter database Test
    set
    auto_create_statistics off,
    auto_update_statistics on
    go
    if object_id('tb') is not null drop table tb
    create table tb
    (
      id int identity(1,1) primary key,
      [Name] char(7000),
      sex nchar(1)
    )
    insert tb([Name],sex) select top 1000 '',N'男' from dbo.syscolumns C1,dbo.syscolumns C2
    --select * from tb
    update tb set sex='女' where id>900
    create index index_tb on tb(id,sex)
    go--在没有统计的情况下
    set statistics io on --打开磁盘活动信息
    select * from tb where sex=N'女'
    set statistics io off--在有统计的情况下,查看磁盘活动信息
    create statistics ON_tb on tb(sex)
    set statistics io on
    select * from tb where sex=N'女'
    set statistics io off
    drop statistics tb.ON_tb
    alter database Test
    set
    auto_create_statistics on
    goset statistics io on --打开磁盘活动信息
    select * from tb where sex=N'女'
    set statistics io offselect * from sysindexes where id=object_id('tb')
    create table tb
    (
      id int identity(1,1) primary key,
      [Name] char(7000),
      sex nchar(1)
    )
    insert tb([Name],sex) select top 5000 '',N'男' from dbo.syscolumns C1,dbo.syscolumns C2update tb set sex=N'女' where id>4000
    create index IX_tb on dbo.tb(id,sex)
    create index IX_tb2 on dbo.tb(sex,id)set statistics io on --打开磁盘活动信息
    select * from tb where sex=N'男'
    set statistics io on
    select * from dbo.tb with(index(IX_tb2)) where id>4000 and sex='女'select * from dbo.tb with(index(IX_tb)) where id>4000 and sex='女'
    set statistics io off
      

  3.   

    深入浅出理解索引结构 
    http://topic.csdn.net/u/20090422/16/d37a2b46-54fb-4be6-96c7-2ae004ca0c42.html
      

  4.   

    并且有时候,在字段上建主键,比如ID,它明显不符合
    动作描述          使用聚集索引    使用非聚集索引 
    ----------------------------------------------------------- 
    列经常被分组排序        应                应 
    返回某范围内的数据    应                不应 
    一个或极少不同值    不应                不应可是SQL自动给它生成了聚集索引,因为它上面是主键,这又怎么回事呢
      

  5.   


    不对哦??当我删了那个聚集索引时,主键也跟着删除了,如何留住主键只删聚集索引呢???
    由于不能Sql Server Management studio用直接删聚集索引,所以我用的" alter   table   tableb   drop   constraint   PK_tableb"
      

  6.   

    看来错了。楼主说的没错,聚集索引删除,主键也删除了。
    if object_id('[tb]') is not null drop table [tb] 
     go 
    create table [tb]([Name] varchar(10))
    alter table tb alter column name varchar(10) not null --修改字段为非空值约束
    alter table tb add constraint pk_tb primary key (name) --新增主键约束
    sp_helpindex tb --查看索引,发现索引名跟主键名一致
    alter table tb drop constraint pk_tb --删除索引
    sp_helpconstraint tb --查看约束,发现没有主键约束了。从新分析楼主的需求,发现SQL主键跟聚集索引是同在的,不能也不需要改变这个设置。
      

  7.   

    表通常具有包含唯一标识表中每一行的值的一列或一组列。这样的一列或多列称为表的主键 (PK),用于强制表的实体完整性。在创建或修改表时,您可以通过定义 PRIMARY KEY 约束来创建主键。 一个表只能有一个 PRIMARY KEY 约束,并且 PRIMARY KEY 约束中的列不能接受空值。由于 PRIMARY KEY 约束可保证数据的唯一性,因此经常对标识列定义这种约束。 如果为表指定了 PRIMARY KEY 约束,则 SQL Server 2005 数据库引擎 将通过为主键列创建唯一索引来强制数据的唯一性。当在查询中使用主键时,此索引还可用来对数据进行快速访问。因此,所选的主键必须遵守创建唯一索引的规则。 创建主键时,数据库引擎 会自动创建唯一的索引来强制实施 PRIMARY KEY 约束的唯一性要求。如果表中不存在聚集索引或未显式指定非聚集索引,则将创建唯一的聚集索引以强制实施 PRIMARY KEY 约束。   聚集索引 聚集索引基于数据行的键值在表内排序和存储这些数据行。每个表只能有一个聚集索引,因为数据行本身只能按一个顺序存储。 每个表几乎都对列定义聚集索引来实现下列功能: 可用于经常使用的查询。 
    提供高度唯一性。 两者的比较下面是一个简单的比较表   主键 聚集索引 
    用途 强制表的实体完整性 对数据行的排序,方便查询用 
    一个表多少个 一个表最多一个主键 一个表最多一个聚集索引 
    是否允许多个字段来定义 一个主键可以多个字段来定义 一个索引可以多个字段来定义 
          
    是否允许 null 数据行出现 如果要创建的数据列中数据存在null,无法建立主键。 创建表时指定的 PRIMARY KEY 约束列隐式转换为 NOT NULL。
     没有限制建立聚集索引的列一定必须 not null . 也就是可以列的数据是 null参看最后一项比较
     
    是否要求数据必须唯一 要求数据必须唯一 数据即可以唯一,也可以不唯一。看你定义这个索引的 UNIQUE 设置。 (这一点需要看后面的一个比较,虽然你的数据列可能不唯一,但是系统会替你产生一个你看不到的唯一列)
     
          
    创建的逻辑 数据库在创建主键同时,会自动建立一个唯一索引。 如果这个表之前没有聚集索引,同时建立主键时候没有强制指定使用非聚集索引,则建立主键时候,同时建立一个唯一的聚集索引
     如果未使用 UNIQUE 属性创建聚集索引,数据库引擎 将向表自动添加一个四字节 uniqueifier 列。 必要时,数据库引擎 将向行自动添加一个 uniqueifier 值,使每个键唯一。此列和列值供内部使用,用户不能查看或访问。
     
    参考:下面这个帖子中大力的回复:http://topic.csdn.net/t/20021212/16/1255429.html
      

  8.   

    if object_id('[tb]') is not null drop table [tb] 
     go 
    create table [tb](id int primary key,[Name] varchar(10))
    create unique index idx_uqe_name on tb(name) --创建唯一非聚集索引就行了。
      

  9.   

    仅从定义来说,主键用于区分表记录,每条记录的主键不同.具体sql server主键自动创建唯一索引.
    可加快查询速度.建议创建表时,先考虑主键的约束逻辑,再考虑索引,查询速度等因素.
      

  10.   


    那是因为你在定义主健前,并没有给表建聚集索引。我在28楼第二行已经说过了。 当然,这个只是针对于sqlserver(oracle下好像也是). sybase下,即便一个表没有聚集索引,建了主健后,也不会自动给主健指定的列加聚集索引。
      

  11.   

    谢谢顾老大,测试结果与你的回答稳合。create table tb_test(id int not null,col int)create unique clustered index idx_tb_test_col on tb_test(col)alter table tb_test add constraint pk_tb_test_id primary key (id)sp_helpindex tb_test
    /*
    index_name              index_description                 index_keys
    ---------------     ----------------------------          -----------------
    idx_tb_test_col clustered, unique located on PRIMARY                 col (col为聚集索引)
    pk_tb_test_id nonclustered, unique, primary key located on PRIMARY id  (主键变成了非聚集索引)
    */
      

  12.   

    未必尽然。
    1. 主键最好建在一个字段上(满足了这条就满足了2NF的要求)
    2. 主键最好建在一个整数型(类似int)的字段上,这是速度最快的
    3. 如果必须要见复合主键,也是可以的,比如<Column1, Column2>作为复合主键。但是你在select语句的where
       子句中,这两个字段出现的顺序一定要和定义主键时一致,即必须是...where Column1 = ... and Column2 = ...,否则主键失效,所以不仅索引要建正确,还要使用正确。
    4. 还有很多其他的技巧,请看:
       http://blog.csdn.net/pathuang68/archive/2009/04/16/4084116.aspx
       原理是想通的。