Mysql ove还不错。)问题是“很多”分区会带来不同的低效率;“太少”分区会导致“何必麻烦”

Mysql ove还不错。)问题是“很多”分区会带来不同的低效率;“太少”分区会导致“何必麻烦”,mysql,performance,query-optimization,Mysql,Performance,Query Optimization,请注意,几乎总是分区表的最佳PK不同于等效的非分区表 请注意,我不同意在vention\u id上进行分区,因为很容易将该列放在PK的开头 分析 假设您搜索一个场馆id并使用我建议的分区和主键,下面是选择的执行方式: 根据日期范围进行筛选。这可能会将活动限制为单个分区 钻取该分区的数据树,以查找该分区的场馆id 从那里跳转数据,降落在所需的区域ID 对于每个,根据日期进一步筛选 我相信MySQL通常一次只能利用一个索引,所以将字段单独索引可能不是最好的选择;我建议尝试在(场馆id,日纪元)或(场

请注意,几乎总是分区表的最佳PK不同于等效的非分区表

请注意,我不同意在
vention\u id
上进行分区,因为很容易将该列放在PK的开头

分析

假设您搜索一个
场馆id
并使用我建议的分区和主键,下面是
选择
的执行方式:

  • 根据日期范围进行筛选。这可能会将活动限制为单个分区
  • 钻取该分区的数据树,以查找该分区的
    场馆id
  • 从那里跳转数据,降落在所需的
    区域ID
  • 对于每个,根据日期进一步筛选

  • 我相信MySQL通常一次只能利用一个索引,所以将字段单独索引可能不是最好的选择;我建议尝试在
    (场馆id,日纪元)
    (场馆id,分区id,日纪元)
    上创建一个综合索引。。。此外,在问题中包含表的创建也不会有任何影响。
    groupby
    通常用于聚合,你想在未分组的字段中选择一个半随机值吗?@uuerdo上面的查询不是整个查询我有一个外部选择,它需要
    groupby
    ,但我没有费心显示,因为这不是问题所在,内部查询(显示)正在减慢速度。我将尝试创建该复合索引。如果GROUPBY用于外部查询,则不需要将其包含在您发布的内容中;原始查询应该有一个
    将您发布的内容与分组依据之前的外部部分分隔开来。@uuerdo包含
    分组依据的原因是,这可能会减慢查询速度。我知道你不知道它为什么会在那里,我现在已经解释过了。我认为问题是由于我所做的编辑。我目前正在添加索引,但我有太多的数据,需要一段时间:)我尝试使用此索引,等待了大约5分钟,但出现了500个错误。是的。。。检查服务器是否仍在执行该查询。既然你说你的表已经分区了,你可以简化这个新索引,只需要有两列
    addindex complex\u idx('day\u epoch','zone\u id')
    。但在这种情况下,我认为您不应该强制使用此索引,而是应该允许服务器优化器分析查询。我刚刚检查了,失败的查询不再运行。那么现在最好不要强制指数?您认为这可能是SQL配置吗?我们使用的AWS RDS服务器具有30GB RAM和8个vCPU,我怀疑服务器规格是否存在问题。是的,我同意服务器硬件看起来不错。只需再尝试一次创建索引,但更简单的索引没有
    vention\u id
    ,因为它已经分区了。关于分区的另一个问题。您是否有办法从
    场馆id
    检测分区id?如果是,我们可以将分区强制添加到查询中,这是有意义的。我尝试了一下,但不幸的是,它没有提高查询速度。我只是觉得奇怪,通过在日期范围内增加一天,它会从0.7秒变为13秒。你会在两个日期之间相遇吗?不,有道理。意味着日期筛选器将大量“返回”到下一个条件。这可能是您的服务器/资源的提示点:)是的,例如,当我在第5次和第9次之间查询时,需要0.7秒,但当我在第5次和第10次之间查询时,需要13秒。因此,仅仅一点点额外的数据就会产生巨大的影响。这可能与MySQL配置有关吗?正如旁注一样,每天返回大约20k条记录,因此,如果再添加一天,就不会有超过100k条记录,因此我认为查询速度不会受到太大影响。@Martijn-优化器可以并且将重新排列
    WHERE
    子句项。手动重新排列它们没有好处。另一方面,复合索引中列的顺序可能非常重要。@Lukerayner-很可能优化器选择了不同的索引来使用,但它弊大于利。为这两种情况提供
    EXPLAIN选择…
    (如果可能)。
    SELECT device_uuid,
         day_epoch,
         is_repeat
    FROM tracking_daily_stats_zone_unique_device_uuids_per_hour
    WHERE day_epoch >= 1552435200
    AND day_epoch < 1553040000
    AND venue_id = 46
    AND zone_id IN (102,105,108,110,111,113,116,117,118,121,287)
    
    CREATE TABLE `tracking_daily_stats_zone_unique_device_uuids_per_hour` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `day_epoch` int(10) NOT NULL,
     `day_of_week` tinyint(1) NOT NULL COMMENT 'day of week, monday = 1',
     `hour` int(2) NOT NULL,
     `venue_id` int(5) NOT NULL,
     `zone_id` int(5) NOT NULL,
     `device_uuid` binary(16) NOT NULL COMMENT 'binary representation of the device_uuid, unique for a single day',
     `device_vendor_id` int(5) unsigned NOT NULL DEFAULT '0' COMMENT 'id of the device vendor',
     `first_seen` int(10) unsigned NOT NULL DEFAULT '0',
     `last_seen` int(10) unsigned NOT NULL DEFAULT '0',
     `is_repeat` tinyint(1) NOT NULL COMMENT 'is the device a repeat for this day?',
     `prev_last_seen` int(10) NOT NULL DEFAULT '0' COMMENT 'previous last seen ts',
     PRIMARY KEY (`id`,`venue_id`) USING BTREE,
     KEY `venue_id` (`venue_id`),
     KEY `zone_id` (`zone_id`),
     KEY `day_of_week` (`day_of_week`),
     KEY `day_epoch` (`day_epoch`),
     KEY `hour` (`hour`),
     KEY `device_uuid` (`device_uuid`),
     KEY `is_repeat` (`is_repeat`),
     KEY `device_vendor_id` (`device_vendor_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=450967720 DEFAULT CHARSET=utf8
    /*!50100 PARTITION BY HASH (venue_id)
    PARTITIONS 100 */
    
    ALTER TABLE tracking_daily_stats_zone_unique_device_uuids_per_hour 
    ADD INDEX complex_idx (`venue_id`, `day_epoch`, `zone_id`)
    
    SELECT device_uuid,
         day_epoch,
         is_repeat
    FROM tracking_daily_stats_zone_unique_device_uuids_per_hour
    USE INDEX (complex_idx)
    WHERE day_epoch >= 1552435200
    AND day_epoch < 1553040000
    AND venue_id = 46
    AND zone_id IN (102,105,108,110,111,113,116,117,118,121,287)
    
    SELECT device_uuid,
         day_epoch,
         is_repeat
    FROM tracking_daily_stats_zone_unique_device_uuids_per_hour
    PARTITION (`p46`)
    WHERE day_epoch >= 1552435200
    AND day_epoch < 1553040000
    AND zone_id IN (102,105,108,110,111,113,116,117,118,121,287)
    
    INDEX(venue_id, zone_id, day_epoch)
    
    PRIMARY KEY(venue_id, zone_id, day_epoch,  -- this order, as discussed above;
                id)    -- to make sure that the entire PK is unique.
    INDEX(id)      -- to keep AUTO_INCREMENT happy
    
    PARTITION BY RANGE(day_epoch)  -- see note below
    
    PRIMARY KEY(venue_id, zone_id, id)