【问题标题】:Why Sequelize issues "SHOW INDEX FROM `table`"?为什么 Sequelize 问题“SHOW INDEX FROM `table`”?
【发布时间】:2016-10-19 23:22:41
【问题描述】:

如果您启用Sequelize 日志记录,您会看到在“同步”阶段和创建表之后,Sequelize 执行SHOW INDEX FROM table 查询。问题是 - 为什么?


更具体地说,这是我正在执行的代码:

var Sequelize = require('sequelize');

var connection = new Sequelize('demo_schema', 'root', 'password');

var Article = connection.define('article', {
    slug: {
        type: Sequelize.STRING,
        primaryKey: true
    },
    title: {
        type: Sequelize.STRING,
        unique: true,
        allowNull: false
    },
    body:  {
        type: Sequelize.TEXT
    }
}, {
    timestamps: false
});

connection.sync({
    force: true,
    logging: console.log
}).then(function () {
   // TODO
});

这是控制台上的输出:

Executing (default): DROP TABLE IF EXISTS `articles`;
Executing (default): DROP TABLE IF EXISTS `articles`;
Executing (default): CREATE TABLE IF NOT EXISTS `articles` (`slug` VARCHAR(255) , `title` VARCHAR(255) NOT NULL UNIQUE, `body` TEXT, UNIQUE `articles_title_unique` (`title`), PRIMARY KEY (`slug`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `articles`

【问题讨论】:

    标签: javascript sql node.js orm sequelize.js


    【解决方案1】:

    Sequelize 使用SHOW INDEX FROM 的原因是为了避免再次将现有索引添加到模型的表中。再次添加现有索引会导致错误。

    Sequelize 目前还不够“智能”,无法理解您尚未定义任何索引。无论如何它都会检查表格。

    在您的情况下,由于您强制同步,因此没有什么不同。这意味着表总是被删除和新创建的。添加新索引时,不会有任何现有索引。

    想象一下,您会指定一个具有如下索引的模型:

    sequelize.define('user', {}, {
      indexes: [
        // Create a unique index on email
        {
          unique: true,
          fields: ['email']
        }
      ]
    })
    这个例子的扩展形式可以在http://docs.sequelizejs.com/en/latest/docs/models-definition/#indexes 找到。

    虚构故事

    如果您昨天使用 Sequelize.sync() 创建了表,今天向您的模型添加了一个新索引,并且不会使用强制同步(因为这样会删除并创建表 -->没有现有索引),Sequelize 将仅添加新索引。

    Sequelize 在这里如何工作?

    Sequelize 通过发出 SHOW INDEX FROM 并将返回值与模型的索引进行比较来确定哪些索引是新的。如果 Sequelize 发现模型中的索引比现有表上的索引更多(或不同),它会将这些索引添加到基础表中。

    可以在GitHub 上找到执行此操作的代码。在下面的代码 sn-p 中,我在各自的代码中添加了一些 cmets:

    // this.QueryInterface.showIndex produces the statement `SHOW INDEX FROM [table of the model]`. It returns a promise containing the found indexes.
    .then(() => this.QueryInterface.showIndex(this.getTableName(options), options))
    // `indexes` will contain the indexes which are present on the existing table.
    // If you force sync, this will always be empty since the table is new.
    .then(indexes => {
      // Assign an auto-generated name to indexes which are not named by the user
      this.options.indexes = this.QueryInterface.nameIndexes(this.options.indexes, this.tableName);
    
      // Fill `indexes` with only the indexes from your model which are not present on the table.
      indexes = _.filter(this.options.indexes, item1 => !_.some(indexes, item2 => item1.name === item2.name));
    
      // .map iterates over `indexes` and adds an index for each entry.
      // Remeber, this is for indexes which are present in the model definition but not present on the table.
      return Promise.map(indexes, index => this.QueryInterface.addIndex(
        this.getTableName(options),
        _.assign({
          logging: options.logging,
          benchmark: options.benchmark,
          transaction: options.transaction
        }, index),
        this.tableName
      ));
    })

    【讨论】:

    • 非常感谢您的详细分解!现在我们有了一个完全清晰的画面。
    • 它是否删除了未在 ORM 中定义的索引?
    • 不,它只会添加新的索引。如果你想删除一个索引,你可以在迁移中使用 queryInterface 的 removeIndex 方法手动完成。更多信息请访问docs.sequelizejs.com/en/latest/docs/migrations/…
    猜你喜欢
    • 2014-09-23
    • 2021-04-11
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多