为什么在MariaDB上通过Sequelize从应用程序运行相同的查询比直接在mysql客户端或CLI上运行它要花费更多的时间?

pbossiut  于 2022-11-08  发布在  Mysql
关注(0)|答案(1)|浏览(129)

对于以下MariaDB模式:

元模式版本

  • 识别码(整数)
  • 名称空间标识(int)
  • 版本(varchar(10))
  • 结构描述(长文字)
  • 注解(中文本)
  • 创建时间(日期时间)
    元数据
  • 标识(整数)[主键]
  • 元标识符(整数)
  • 版本编号(整数)
  • 元模式版本标识(整数)- [FK到元模式版本]
  • 标签(varchar(30))
  • 标记值(varchar(100))
  • 元(长文本)
  • 注解(中文本)
  • 被删除(tinyint(1))
  • updated_at(日期时间)
  • 更新者(varchar(100))

以下是meta表上的索引:

  • id -主键- BTREE -唯一
  • meta_schema_version_id -外键- BTREE -不唯一
  • idx配置标识- BTREE -不唯一
    meta表中有一百多万条记录。

我使用Sequelize来获取一个分页列表,如下所示:

metas = await this.meta.findAndCountAll({
                attributes: ['id', 'tag', 'tagValue', ...versionAttribute],
                include: [
                  {
                    model: MetaSchemaVersion,
                    attributes: ['version'],
                  },
                ],
                where: {
                  metaSchemaVersionId: schemaVersion.id,
                  isDeleted: {
                    [Op.eq]: 0,
                  },
                },
                limit,
                offset,
              });

Sequelize会记录与上述函数对应的以下2个查询:查询1:

SELECT  count(*) AS `count`
    FROM  `meta` AS `Meta`
    WHERE  `Meta`.`meta_schema_version_id` = 1
      AND  `Meta`.`is_deleted` = 0

查询2:

SELECT  `id`, `tag`, `tag_value` AS `tagValue`,
        `comment`, `updated_at` AS `updatedAt`,
        `updated_by` AS `updatedBy`,
        `meta_schema_version_id` AS `metaSchemaVersionId`,
        `meta`
    FROM  `meta` AS `Meta`
    WHERE  `Meta`.`meta_schema_version_id` = 1
      AND  `Meta`.`is_deleted` = 0
    LIMIT  0, 10

我启用了非常低的long_query_time(0.0001)的慢速查询日志
慢速查询日志的查询时间为:

  • 查询1:00:00:00.612878
  • 查询2:00:00:00.894041

当直接在CLI上运行相同的查询时,两个查询的查询时间都显示为**~00:00:00.0005**
为什么直接在CLI上运行与通过Sequelize ORM运行在查询时间上会有如此大的差异?

SHOW PROFILE对慢速查询给出以下响应

[
  { Status: 'Starting', Duration: '0.000026' },
  { Status: 'Opening tables', Duration: '0.000025' },
  { Status: 'System lock', Duration: '0.000003' },
  { Status: 'table lock', Duration: '0.000004' },
  { Status: 'Opening tables', Duration: '0.000002' },
  { Status: 'After opening tables', Duration: '0.000100' },
  { Status: 'closing tables', Duration: '0.000003' },
  { Status: 'Unlocking tables', Duration: '0.000003' },
  { Status: 'closing tables', Duration: '0.000073' },
  { Status: 'checking permissions', Duration: '0.000005' },
  { Status: 'Opening tables', Duration: '0.000013' },
  { Status: 'After opening tables', Duration: '0.000004' },
  { Status: 'System lock', Duration: '0.000004' },
  { Status: 'table lock', Duration: '0.000006' },
  { Status: 'init', Duration: '0.000033' },
  { Status: 'Optimizing', Duration: '0.000018' },
  { Status: 'Statistics', Duration: '0.000074' },
  { Status: 'Preparing', Duration: '0.000024' },
  { Status: 'Executing', Duration: '0.000002' },
  { Status: 'Sending data', Duration: '0.880704' },
  { Status: 'End of update loop', Duration: '0.000016' },
  { Status: 'Query end', Duration: '0.000003' },
  { Status: 'Commit', Duration: '0.000005' },
  { Status: 'closing tables', Duration: '0.000003' },
  { Status: 'Unlocking tables', Duration: '0.000002' },
  { Status: 'closing tables', Duration: '0.000043' },
  { Status: 'Starting cleanup', Duration: '0.000003' },
  { Status: 'Freeing items', Duration: '0.000010' },
  { Status: 'Updating status', Duration: '0.000015' },
  { Status: 'Logging slow query', Duration: '0.000006' },
  { Status: 'Opening tables', Duration: '0.000016' },
  { Status: 'System lock', Duration: '0.000002' },
  { Status: 'table lock', Duration: '0.000003' },
  { Status: 'Opening tables', Duration: '0.000002' },
  { Status: 'After opening tables', Duration: '0.000059' },
  { Status: 'closing tables', Duration: '0.000002' },
  { Status: 'Unlocking tables', Duration: '0.000002' },
  { Status: 'closing tables', Duration: '0.000005' },
  { Status: 'Reset for next command', Duration: '0.000238' }
]

更新1:我的原始帖子中提到的查询是不正确的。我在复制SQL查询时已经在ORM代码中注解了连接部分。正确的查询是:
查询1:

SELECT count(Meta.id) AS count FROM meta AS Meta LEFT OUTER JOIN meta_schema_version AS metaSchemaVersion ON Meta.meta_schema_version_id = metaSchemaVersion.id WHERE Meta.meta_schema_version_id = 1 AND Meta.is_deleted = 0;

查询2:

SELECT Meta.id, Meta.tag, Meta.tag_value AS tagValue, Meta.comment, Meta.updated_at AS updatedAt, Meta.updated_by AS updatedBy, Meta.meta_schema_version_id AS metaSchemaVersionId, Meta.meta, metaSchemaVersion.id AS metaSchemaVersion.id, metaSchemaVersion.version AS metaSchemaVersion.version FROM meta AS Meta LEFT OUTER JOIN meta_schema_version AS metaSchemaVersion ON Meta.meta_schema_version_id = metaSchemaVersion.id WHERE Meta.meta_schema_version_id = 1 AND Meta.is_deleted = 0 LIMIT 0, 20;
moiiocjp

moiiocjp1#

这可能对两个查询的Meta都有利:

INDEX(meta_schema_version_id, is_deleted)   -- (the column order does not matter)

但是,没有ORDER BYLIMIT将给出它想要给出的任何行。
(我对X1 M5 N1 X有非常负面的看法。注意几乎所有的时间都在神秘的“发送数据”中。这很常见。)
直接在CLI上运行时的相同查询
这有两个 * 可能 * 的原因。

SELECT SQL_NO_CACHE ...`
  • 这避免了“查询高速缓存”,其中查询及其结果被高速缓存;因为 second 运行基本上是瞬时的,例如00:00:00.0005。
  • 或者......第一次运行可能已经从磁盘中提取了大量数据,因此由于数据缓存在RAM中,第二次运行的速度会快很多。

因此,添加该标志,运行查询两次,进行第二次计时。
我从本地开发机器上的应用服务器发出请求。
测试网络延迟(开销)的一种方法是对简单的SELECT 1;查询进行计时。
查询1必须扫描整个表。使用我的索引,它将扫描索引的一部分。
查询2(没有ORDER BY)扫描表,直到找到10行与WHERE子句匹配。

相关问题