【问题标题】:Can you have multiple Keys in SQL and why would you want that?你可以在 SQL 中有多个键,你为什么要这样?
【发布时间】:2011-09-16 20:46:28
【问题描述】:

您是否有理由希望在一个 TABLE 中拥有多个 KEY?在一个表中有多个 KEY 有什么意义?

这是我找到的一个例子:

CREATE TABLE orders(
id INT UNSIGNED NOT NULL AUTO INCREMENT,
user_id INT UNSIGNED NOT NULL,
transaction_id VARCHAR(19) NOT NULL,
payment_status VARCHAR(15) NOT NULL,
payment_amount DECIMAL(15) NOT NULL,
payment_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(id),
KEY(user_id),
)

此外,您会注意到 DBase 程序员不会将 transaction_id 设为 KEY。这是有原因的吗?

【问题讨论】:

    标签: mysql sql key


    【解决方案1】:

    KEY 在 MySQL 中是“索引”的替代语法。
    索引在数据库中很常见,但它们还没有被 ANSI 覆盖——这纯粹是奇迹,事情和它们一样相似。将多个索引关联到一个表是很常见的——因为索引以更新/删除/插入速度为代价来改进数据检索。

    请注意,如果表的主键尚不存在索引,MySQL (5.x?) 会自动创建索引。

    【讨论】:

    • SQL 标准定义了一种关于 Codd 规则的关系完整的语言(包括他犯的一些错误:) 根据定义它避免对底层存储做出假设包括索引。
    【解决方案2】:

    有几个可能的原因。

    • 提高搜索性能(当 WHERE 子句使用 KEY 字段时,它执行得更快)
    • 限制表格内容(当对列使用唯一键时,它不能有两次或多次相同的值)

    这些是最常见的原因。

    【讨论】:

    • 在这种情况下,我为什么不把所有的东西都变成钥匙呢?这样我可以更快地搜索所有内容?
    • 更新许多索引是昂贵的。这会减慢您的更新和插入速度。
    • @Rasika 所以你的意思是,如果我将一列设为键,我必须确保更新与此特定表中的同一键相关的所有其他键?这就是它贵的原因吗?
    • 不,密钥的更新将由数据库服务器自动进行。但是,由于它必须进行更多更新,从而加载服务器。这就是为什么您在进行批量插入时有一个禁用键选项来加快插入速度。每次插入完成时,服务器都会更新该表中的所有相关索引。不一定在相关表上。
    • @Rasika 有什么地方可以让我了解如何自动更新密钥?
    【解决方案3】:

    在 SQL 中,每个表可能只有一个 PRIMARY KEY

    KEY(foo) 是标准 SQL 中的虚假语法。在 MySQL 中,KEY fooINDEX foo 的名称不佳的同义词,并且没有施加 UNIQUE 约束。 (它的名字很糟糕,因为它实际上与键的功能无关。)

    可能有多个UNIQUE INDICES可以起到“候选键”的作用。 (可以在没有关联 INDEX 的情况下指定唯一约束,但“键”的点通常是快速查找。)PRIMARY KEY 的点是唯一标识单个记录,几乎完全由 INDEX 支持,甚至可能与数据的聚类直接相关。

    只应使用确保数据有效性满足性能要求所需的最少量的[唯一]索引——它们也会对查询引擎造成性能损失以及额外的更新和维护费用。

    非唯一 INDEX(INDEX foo,或者对于 MySQL,KEY foo)纯粹是为了让数据库优化查询。它们真正映射到“键”,可能被称为“覆盖索引”;如果查询规划器选择了这些索引,即使它们对逻辑模型本身没有任何添加,它们也可以帮助提高性能。 (出于性能原因,数据库引擎可能要求索引覆盖 FOREIGN KEYS。)

    在这种情况下,在 user_id 上创建一个 INDEX(不要认为“KEY”!)通常会(极大地)加快使用以下子句的查询:

    ... WHERE user_id = {somenumber}
    

    如果没有 INDEX,上述查询将需要 FULL TABLE SCAN(例如,读取所有记录)。

    虽然我不知道为什么不将transaction_id 设为索引,但它可能不是必需的(甚至不利于给定的访问模式)——考虑每个 需要快速的查询:

    1. 不使用transaction_id或;
    2. 还有user_id = ... 或其他可以利用索引的限制。也就是说,在WHERE user_id = ... AND transaction_id = ... 这样的情况下,查询规划器可能首先找到匹配用户的记录,然后再寻找匹配的transaction_id——它仍然必须进行扫描,但只能在比原始表小得多的数据集上。只有普通的WHERE transaction_id = ... 必然需要全表扫描。

    如果有疑问,请使用 EXPLAIN -- 或其他 query analyzer -- 并查看 MySQL 认为 它应该做什么。最后一点,有时估计的查询执行计划可能与实际执行计划不同,过时的统计数据会使查询计划者选择不理想的计划。

    编码愉快。

    【讨论】:

      【解决方案4】:

      “键”可能指以下之一:

      您可能需要多个,因为您需要在一个表中实现多个这些功能。这其实很常见。

      【讨论】:

        【解决方案5】:

        在数据库理论中,键是强制唯一性的约束。一个 relvar(类似于 SQL 表)可能确实有多个候选键。一个经典的例子是一组化学元素,其中名称、符号、原子序数和原子量都是关键(人们仍然希望在其中添加自己的代理键;)

        MySQL 延续了滥用 KEY 一词的悠久传统,将其设为 INDEX 的同义词。显然,在给定的一组环境下,一个 MySQL 表可以有尽可能多的索引来满足性能的需要。

        从您的 SQL DDL 看来,ID 显然是一个代理键,因此我们必须寻找一个自然键,并且没有太多可做的事情。虽然transaction_id 可能是候选人,但订单可能涉及多个交易并非不可想象。实际上,我认为审核员会怀疑同一用户同时发出的多个订单,因此建议user_idpayment_time 的组合应该是关键。但是,如果transaction_id 不是键,则该表将不会完全规范化。因此,我会给设计师带来疑问,并假设transaction_id 也是一个关键。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多