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

在索引布尔列与日期时间列上查询的性能

乐正瑞
2023-03-14
问题内容

如果索引是在datetime类型列而不是boolean类型列上设置(并且查询是在该列上进行的),则查询性能是否存在显着差异?

在我目前的设计中,我有2列:

  • is_activeTINYINT(1),已 索引
  • deleted_at 约会时间

查询是 SELECT * FROM table WHERE is_active = 1;

如果我deleted_at改为在列上创建索引并运行这样的查询,会不会更慢SELECT * FROM table WHERE deleted_at is null;


问题答案:

这是一个具有1000万行的MariaDB(10.0.19)基准测试(使用sequence插件):

drop table if exists test;
CREATE TABLE `test` (
    `id` MEDIUMINT UNSIGNED NOT NULL,
    `is_active` TINYINT UNSIGNED NOT NULL,
    `deleted_at` TIMESTAMP NULL,
    PRIMARY KEY (`id`),
    INDEX `is_active` (`is_active`),
    INDEX `deleted_at` (`deleted_at`)
) ENGINE=InnoDB
    select seq id
        , rand(1)<0.5 as is_active
        , case when rand(1)<0.5 
            then null
            else '2017-03-18' - interval floor(rand(2)*1000000) second
        end as deleted_at
    from seq_1_to_10000000;

为了衡量我执行查询后使用set profiling=1和运行的时间show profile。从概要分析结果中,我可以得出的价值,Sending data因为其他所有内容的总和都小于一毫秒。

TINYINT 索引:

SELECT COUNT(*) FROM test WHERE is_active = 1;

运行时间: 〜738毫秒

TIMESTAMP 索引:

SELECT COUNT(*) FROM test WHERE  deleted_at is null;

运行时间: 〜748毫秒

索引大小:

select database_name, table_name, index_name, stat_value*@@innodb_page_size
from mysql.innodb_index_stats 
where database_name = 'tmp'
  and table_name = 'test'
  and stat_name = 'size'

结果:

database_name | table_name | index_name | stat_value*@@innodb_page_size
-----------------------------------------------------------------------
tmp           | test       | PRIMARY    | 275513344 
tmp           | test       | deleted_at | 170639360 
tmp           | test       | is_active  |  97107968

请注意,虽然TIMESTAMP(4字节)是TYNYINT(1字节)的4倍,但索引大小甚至不是两倍。但是,如果索引大小不适合内存,则索引大小可能很大。因此,当我innodb_buffer_pool_size从更改为时1G50M我得到以下数字:

  • TINYINT: ~ 960 msec
  • TIMESTAMP: ~ 1500 msec

为了更直接地解决这个问题,我对数据做了一些更改:

  • 我使用DATETIME代替TIMESTAMP
  • 由于条目通常很少被删除,因此我使用rand(1)<0.99(已删除1%)而不是rand(1)<0.5(已删除50%)
  • 表大小从10M行更改为1M行。
  • SELECT COUNT(*) 变成 SELECT *

索引大小:

index_name | stat_value*@@innodb_page_size
------------------------------------------
PRIMARY    | 25739264
deleted_at | 12075008
is_active  | 11026432

deleted_at尽管非空的DATETIME需要8个字节(MariaDB),但由于99%的值为NULL,因此索引大小没有显着差异。

SELECT * FROM test WHERE is_active = 1;      -- 782 msec
SELECT * FROM test WHERE deleted_at is null; -- 829 msec

删除两个索引后,两个查询将在大约350毫秒内执行。并删除查询将在280毫秒内执行的is_activedeleted_at is null

请注意,这仍然不是现实的情况。您不太可能希望从1M中选择990K行并将其交付给用户。表中可能还会有更多列(可能包括文本)。但是它表明,您可能不需要该is_active列(如果它不添加其他信息),并且在最好的情况下,任何索引对于选择未删除的条目都是无用的。

但是,索引对于选择已删除的行可能很有用:

SELECT * FROM test WHERE is_active = 0;

有索引的执行时间为10毫秒,无索引的执行时间为170毫秒。

SELECT * FROM test WHERE deleted_at is not null;

有索引的执行时间为11毫秒,无索引的执行时间为167毫秒。

删除该is_active列时,它在有索引的情况下以4毫秒执行,在没有索引的情况下以150毫秒执行。

因此,如果这种情况能以某种方式适合您的数据,那么结论将是:如果您很少选择已删除的条目,则删除该is_active列,并且不要在该列上创建索引deleted_at。或根据您的需求调整基准并做出自己的结论。



 类似资料:
  • 问题内容: 尽管至少有两个 关于如何在Python的库中为DataFrame编制索引的优秀教程,但我仍然无法找到一种优雅的方法来编写多个列。 我已经发现(我认为是)这样一种不太优雅的方式 但这并不漂亮,可读性得分很低(我认为)。 有没有更好,更Python风格的方法? 问题答案: 这是一个优先运算符问题。 您应该添加额外的括号以使多条件测试正常工作: 您提到的教程的这一部分显示了带有几个布尔条件的

  • 问题内容: 所以我想要实现的是与每个索引的自定义可搜索字段部分匹配。我生成一个带有要搜索的值的值,如果该值不止一个单词,则每个单词又生成另一个值(我可以使用,但它有错误,或者具有未记录的设置)。 在这种情况下,我正在寻找;查询如下所示: 我的目标搜索是获取首先具有的结果,然后搜索just 或。 此示例返回4个具有的结果,然后是仅具有的结果,然后是个更多的结果。 如何提高具有完整搜索值的结果?(“电

  • 我们在各种搜索应用程序中使用solr索引。在大多数情况下,我们使用它就像您使用管理界面一样。例如: 这个很好用 我的问题是,在一个应用程序中,我们直接对索引使用复杂的lucene查询(不使用solr),在这些查询中,我找不到如何搜索日期字段 在模式中。xml: 看起来solr将日期存储为以毫秒为单位的unix时间,当从索引中提取字段时,它看起来1336867200000 在Lucene中,我尝试了

  • 问题内容: 在查询1上,即使id是索引列,也会执行全表扫描。查询2达到相同的结果,但速度更快。如果运行查询1返回索引列,则它会快速返回,但是如果返回未索引列或整个行,则查询将花费更长的时间。 在查询3中,它运行很快,但是列“代码”是VARCHAR2(10)而不是NUMBER(12),并且以与“ id”相同的方式索引。 为什么查询1不选择应使用索引?是否应该更改某些内容以使索引数字列更快地执行? [

  • 问题内容: 我有一段代码应该在其中创建总机。我想返回所有打开的开关的列表。这里的“开”等于和“关”等于。因此,现在我只想返回所有值及其位置的列表。这就是我所拥有的,但它只返回第一次出现的位置(这只是我的代码的一部分): 这只会返回“ 4” 问题答案: 使用,返回找到的第一个匹配项的索引。 对于庞大的列表,最好使用:

  • 我在ES中有两个问题。对于同一组文档,两者的周转时间都不同。两者在概念上都在做同样的事情。我没有什么疑问 1-这两者之间有什么区别?2-哪个更好使用?3-如果两者相同,为什么表现不同? 映射: 更新1: 我在同一组数据上尝试了bool/必须查询和bool/过滤器查询,但我发现了奇怪的行为 1-bool/必须查询能够搜索所需的文档 2-虽然bool/filter无法搜索文档。如果我删除第二个字段条件