当前位置: 首页 > 面试题库 >

如何为具有两个范围条件的查询建立索引?

干浩阔
2023-03-14
问题内容

系列中的下一个’‘

CREATE TABLE `Alarms` (
  `AlarmId` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `DeviceId` BINARY(16) NOT NULL,
  `Code` BIGINT(20) UNSIGNED NOT NULL,
  `Ended` TINYINT(1) NOT NULL DEFAULT '0',
  `NaturalEnd` TINYINT(1) NOT NULL DEFAULT '0',
  `Pinned` TINYINT(1) NOT NULL DEFAULT '0',
  `Acknowledged` TINYINT(1) NOT NULL DEFAULT '0',
  `StartedAt` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
  `EndedAt` TIMESTAMP NULL DEFAULT NULL,
  `MarkedForDeletion` TINYINT(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`AlarmId`),
  KEY `Key1` (`Ended`,`Acknowledged`),
  KEY `Key2` (`Pinned`),
  KEY `Key3` (`DeviceId`,`Pinned`),
  KEY `Key4` (`DeviceId`,`StartedAt`,`EndedAt`),
  KEY `Key5` (`DeviceId`,`Ended`,`EndedAt`),
  KEY `Key6` (`MarkedForDeletion`,`DeviceId`,`Acknowledged`,`Ended`,`StartedAt`),
  KEY `Key7` (`MarkedForDeletion`,`DeviceId`,`Ended`,`Pinned`,`EndedAt`)
) ENGINE=INNODB;

This query is quite slow when the timestamps are chosen such that many rows
are matched:

SELECT (((UNIX_TIMESTAMP(`StartedAt`)) DIV 900) * 900) AS `Period_TS`,
COUNT(`AlarmId`) AS `n`
FROM `Alarms`
WHERE `StartedAt` >= FROM_UNIXTIME(1518990000)  
AND `StartedAt` <  FROM_UNIXTIME(1518998400) 
AND `DeviceId` IN (
    UNHEX('00030000000000000000000000000000'),
    UNHEX('000300000000000000000000000181cd'),
    UNHEX('000300000000000000000000000e7cf6'),
    UNHEX('000300000000000000000000000e7cf7'),
    UNHEX('000300000000000000000000000f423f')
) AND `MarkedForDeletion` = FALSE
GROUP BY `Period_TS` ASC;

我相信这是因为我在两个字段(DeviceId和StartedAt)上混合了范围条件。

如果是这样,我该怎么办才能解决问题?也许有什么
触发索引合并的使用?


问题答案:

IN在=“范围”和“范围”之间。因此,我对
问题的标题有所疑问。实际上,不可能优化两个范围。在IN加上一系列
具有优化的一些机会。

基于

WHERE `StartedAt` >= FROM_UNIXTIME(1518990000)  
AND   `StartedAt` <  FROM_UNIXTIME(1518998400) 
AND `DeviceId` IN (
    UNHEX('00030000000000000000000000000000'),
    UNHEX('000300000000000000000000000181cd'),
    UNHEX('000300000000000000000000000e7cf6'),
    UNHEX('000300000000000000000000000e7cf7'),
    UNHEX('000300000000000000000000000f423f')
) AND `MarkedForDeletion` = FALSE

I would provide 2 indexes and let the Optimizer decide which to use:

INDEX(MarkedForDeletion, StartedAt, DeviceId)
INDEX(MarkedForDeletion, DeviceId, StartedAt)

一些较新的MySQL / MariaDB版本可以跳过并利用第二个索引中的所有3
列。在所有版本中,任一 索引的前2列均使其成为候选值。该选择可能受统计驱动,并且可能 (也可能不是)“正确”的选择。

既然AlarmId不能NULL,请使用模式:COUNT(*)

进行更改后,我的每个索引都被“覆盖”了,从而使性能得到了进一步的提升。



 类似资料:
  • 问题内容: 我如何结合这两个更新语句: 问题答案: 您可以使用CASE表达式,如下所示:

  • 我有一个表“Quote”,映射在hibernate中,它有一个由整数id和日期组成的复合键,还有几个附加列。我想编写一个条件查询,它使用DetachedCriteria来获取每个id中日期最长的行。 在sql中,我可能会编写一个查询,比如 在hibernate中,我认为可以像这样为“group by”子查询创建DetachedCriteria(其中Quote是映射表的类,“Qid”是键的复合id类

  • 当我在Kibana开发控制台上运行下面的弹性搜索DSL查询时,它会正确返回结果,我试图通过基于URI的查询运行相同的结果,因为HTTP URL不起作用。我尝试了doc和良好的搜索,没有得到确切的方式来帧这个查询为基于HTTP的GET网址。 有什么提示吗。

  • > 每个对象表示一个重复发生的事件。该事件可以在多个日期发生。因此,请考虑以下内容: 我有一个日历在客户端,用户可以选择一个日期范围。 > 对所选日期范围的每个条目进行调用,并在客户端处理聚合。问题是会有大量的读取,因为我们会多次读取重叠的日期范围内的同一个列表对象。 尝试使用类似ElasticSearch/Algolia的服务来完成此操作 任何建议都会很有帮助!

  • 我有一个大约为100GB的cosmos数据库。我成功地创建了一个漂亮的分区键,我在70M记录上有大约4600个分区,但是我仍然需要查询两个存储为字符串的日期时间字段,而不是纪元格式。 示例json: 我注意到当我做中选择*以及当我做

  • 可不可以有一种方式提前定义好 where 条件,然后将这种定义好的条件又可以重新组合呢?答案就是 Scope。 const Project = sequelize.define('project', { // Attributes }, { defaultScope: { where: { active: true } }, scopes: {