代码之家  ›  专栏  ›  技术社区  ›  Denis Palnitsky

由3个文本字段组成的唯一索引

  •  1
  • Denis Palnitsky  · 技术社区  · 14 年前

    领域:

    • “用户”varchar(128)
    • “内容”文本`

    用例:

    1. 查找产品的所有评论
    2. 插入或更新评论

    我在案例2中遇到了问题,因为我需要找出是否已经存在评审(使用相同的produtcId、用户和源进行评审)。

    问:用produtcId+user+Source创建主键或唯一索引好吗?

    1 回复  |  直到 14 年前
        1
  •  3
  •   KM.    14 年前

    这是一个自然键变坏的例子,在我的书中varchar(128)对于PK来说太大了。它迫使你在评审表中有一个大的fat(非常宽的)PK或index。我会这样做:

    Products
    ProductID     int autoincrement PK
    ProductNumber char(14)
    ProductName...
    ...
    
    Users
    UserID        int autoincrement PK
    UserName      varchar(128)
    ...
    
    ProductSources
    ProductSourcID  int autoincrement PK
    ProductSource   varchar(128)
    ...
    
    Reviews
    ReviewID      int autoincrement PK
    ProductID     int FK
    UserID        int FK
    ProductSourcID  int FK
    ReviewContent text
    ....
    

    您可以考虑进行PK:ProductID+UserID+ProductSourcID。但是,如果您需要FK到另一个表中的Reviews,那么您需要在ProductID+UserID+ProductSourcID之间拖动。我更喜欢FK来复习。

    在任何情况下,int+int+int自动递增ProductID+UserID+ProductSourcID在磁盘存储和缓存使用方面都比char(14)+varchar(128)+varchar(128)版本要好得多。对于数据库来说,使用和存储固定宽度的int+int+int索引值比char(14)+varchar(128)+varchar(128)版本要容易得多。

    此外,通过使用自动增量PKs,用户可以更改他们的用户名(结婚/离婚),而不是破坏所有的FKs。它将强制所有ProductSource值标准化,而不是自由文本,无法加入。

    编辑 根据OP的评论:

    这将使情况急剧复杂化 用户或源的其他信息。 使用这个字段的哈希值怎么样 作为主键?

    我不知道身份证是怎么让插入复杂化的。但是,如果您不能/不愿意更改其他表的PKs,那么哈希是最好的方法,但我不会将其作为PK。千万不要让散列成为PK,可能会发生冲突,阻止插入合法数据。使用auto generate INT作为PK并添加一个哈希列。你应该这样做。在Reviews中创建一个名为“ReviewHash”的新列,并向其中添加一个索引,如果预期会发生许多冲突(多个不同的行具有相同的哈希值),则可以将productid、user和source列包含为“covered columns”。另外,做 WHERE 像这样做:

    FROM Reviews
     ....
    WHERE 
        YourHashFunction(CONCAT(given_productid,'||',given_user,'||',given_source))=Review.Hash
        AND Review.productid=given_productid 
        AND Review.user=given_user 
        AND Review.source=given_source`  
    

    如果您执行以下查询:

    WHERE 
        YourHashFunction(CONCAT(given_productid,'||',given_user,'||',given_source))
            =YourHashFunction(CONCAT(Review.productid,'||',Review.user,'||',Review.source))
    

    那么就不能使用索引,查询必须应用 YourHashFunction 表中的每一行。另外,如果不检查productid、user和source,则会得到哈希值相同但实际值不同的结果。