Mysql存储函数和分组最小值[关闭]

2024-01-15

Schema

数据库架构得到简化
活动表
该表存储事件。

CREATE TABLE `Events` (
`event_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`isPublic` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

位置表
存储位置的简单桌子。一项活动可以在多个地点举行。

CREATE TABLE `Places` (
`place_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`latitude` double NOT NULL,
`longitude` double NOT NULL,
PRIMARY KEY (`place_id`),
KEY `latind` (`latitude`,`longitude`)
) ENGINE=InnoDB CHARSET=latin1;

规则表
存储事件时间表的表。一项活动可以有多个时间表。所有日期均采用 unixtimestamp 格式。常规意味着该规则有一些重复的计划,存储在 RegularRules 表中。

CREATE TABLE `Rules` (
`rule_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`start_date` int(11) NOT NULL,
`end_date` int(11) NOT NULL,
`regular` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`rule_id`),
KEY `endindx` (`end_date`)
) ENGINE=InnoDB CHARSET=latin1;

常规规则
以以下格式存储可重复计划的表。 day_start/end 表示从当天开始 (00:00) 到事件开始的秒数。例如,活动每周一的 10:00 至 18:00 举行。我们将存储start_date and end_date在规则表中,这些值代表事件的时间限制。在 RegularRules 表中,我们将有 36000mon_start和 64800mon_end.

CREATE TABLE `RegularRules` (
`repetition_id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`rule_id` bigint(20) unsigned NOT NULL,
`mon_start` int(11) DEFAULT NULL,
`tue_start` int(11) DEFAULT NULL,
`wed_start` int(11) DEFAULT NULL,
`th_start` int(11) DEFAULT NULL,
`fr_start` int(11) DEFAULT NULL,
`sat_start` int(11) DEFAULT NULL,
`sun_start` int(11) DEFAULT NULL,
`mon_end` int(11) DEFAULT NULL,
`tue_end` int(11) DEFAULT NULL,
`wed_end` int(11) DEFAULT NULL,
`th_end` int(11) DEFAULT NULL,
`fr_end` int(11) DEFAULT NULL,
`sat_end` int(11) DEFAULT NULL,
`sun_end` int(11) DEFAULT NULL,
PRIMARY KEY (`repetition_id`),
KEY `fk_rule_id_regularrules_idx` (`rule_id`),
CONSTRAINT `fk_rule_id_regularrules` FOREIGN KEY (`rule_id`) 
REFERENCES `Rules` (`rule_id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB  CHARSET=latin1;

活动-地点-规则
连接以上所有表格的表格。

CREATE TABLE EPR (
`holding_id` bigint(30) NOT NULL AUTO_INCREMENT,
`event_id` bigint(20) unsigned NOT NULL,
`place_id` bigint(20) unsigned NOT NULL,
`rule_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`holding_id`),
UNIQUE KEY `compound` (`place_id`,`event_id`,`rule_id`),
KEY `FK_Places-Company Events-Rules_Events_event_id` (`event_id`),
KEY `FK_Places-Company Events-Rules_Places_place_id` (`place_id`),
KEY `FK_Places-Company Events-Rules_Rules_rule_id` (`rule_id`),
CONSTRAINT `FK_Places-Company Events-Rules_Events_event_id` 
FOREIGN KEY  (`event_id`) REFERENCES `Events` (`event_id`) ON DELETE CASCADE 
ON UPDATE  CASCADE,
CONSTRAINT `FK_Places-Company Events-Rules_Rules_rule_id` 
FOREIGN KEY  (`rule_id`) REFERENCES `Rules` (`rule_id`) ON DELETE CASCADE ON  
UPDATE CASCADE,
CONSTRAINT `fk_place_id_pcerc` FOREIGN KEY (`place_id`) 
REFERENCES `Places` (`place_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB CHARSET=latin1;

存储功能

有两个存储函数。开始 and GETENDS。参数:rule_id、timestamp、curtimestamp。Timestamp是当天的unix时间戳,curtimestamp是当天开始的unix时间戳。 这些函数的工作原理如下。对于每个规则,它们返回规则的开头(开始)和结束(结束)。如果规则不可重复,则返回start_date and end_date存储在规则表中。如果规则是可重复的,他们会构建begins and endsRegularRules 表中最接近的非空 day_start/day_end 的值。例如,有一个事件有 2 个规则。第一个不可重复开始start_timestamp并结束end_timestamp。第二个是可重复的,并且只有两个非空字段:mon_start = 36000 and mon_end = 64800. GETBEGINS将转向mon_start在unix时间戳中,基于当前unix时间戳和当天开始的当前unix时间戳。GETBEGINS工作原理类似。如有需要,将提供这些功能的代码。

有问题的查询

该查询应该返回ongoing地理上和时间上最接近的事件。地方应该是不同的。因此,查询应该为每个地点返回按时间顺序排列最接近的事件,并在最后根据时间和距离以及一些系数对结果值进行排序(我认为排序部分将转移到服务器端语言,如 PHP。如果您对这种排序有建议,我愿意接受任何解决方案)。例如,附近10家电影院有5部电影。每个电影院有 100 个时间表。查询应为每个电影院返回按时间顺序最接近的电影,然后根据时间和距离两个值对电影和电影院进行排序。

意向查询
latpoint,longpoint,r - 是传递给脚本的坐标和半径, curstamp - 一天开始的unix时间戳, 时间戳 - 当前unix时间戳

SELECT 
    epr.event_id,
    epr.place_id,
    epr.rule_id,
    (6371 * ACOS(COS(RADIANS(latpoint)) * COS(RADIANS(latitude)) *  
    COS(RADIANS(longitude) - RADIANS(longpoint)) + SIN(RADIANS(latpoint)) * 
    SIN(RADIANS(latitude)))) AS distance,
    p.latitude,
    p.longitude,
    GETBEGINS(r.rule_id, curstamp, timestamp) AS begins,
    GETENDS(r.rule_id, curstamp, timestamp) AS ends,
    MIN(ABS(GETBEGINS(r.rule_id, curstamp, timestamp) - timestamp)) AS   
    time_min
FROM
    Events e
        INNER JOIN
    EPR epr ON e.event_id = epr.event_id
        INNER JOIN
    Places p ON epr.place_id = p.place_id
        INNER JOIN
    Rules r ON epr.rule_id = r.rule_id
WHERE
    r.end_date >= timestamp
        AND latitude BETWEEN latpoint - (r / 111.045) AND latpoint + (r /   
        111.045)
        AND longitude BETWEEN longpoint - (r / (111.045 *  
        COS(RADIANS(latpoint)))) AND longpoint + (r / (111.045 * 
        COS(RADIANS(latpoint))))
        AND e.isPublic = 1
GROUP BY epr.place_id

如主题中所述,此查询混合返回值。更具体地说,它与 place_id 组匹配错误的rule_id,begins,ends。 而且这个查询的性能很差。表的大小:事件 - 3000 行,地点 - 8000 行,规则 18000 行,EPR - 15000 行。使用索引提示时,这些查询大约需要 1.8 秒(use index compound) 和 1.2 没有一个。不使用索引提示查询会进行全表扫描。 我读过了官方 mysql 文档 http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html关于这个主题。然而,由于用户计算的值,他们的解决方案并不适用(GETBEGINS and GETENDS).

Question

中提供的查询预期查询部分由于方式存在分组最小值问题mysql 处理分组依据 http://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html。那么可能的解决方案是使函数 GET BEGINS 和 GETENDS 用户定义的聚合函数这样 mysql 可能会返回适当的结果吗?这个解决方案合乎逻辑吗?遗嘱制作功能GETBEGINS and GETENDS汇总帮助?在这种情况下mysql会返回适当的数据吗?

结论

欢迎对所提供的解决方案、新解决方案、索引和数据库架构发表评论。


不保证分组最大值有效。事实上,MariaDB 破坏了它,但提供了一个设置来恢复它。这就是我指的:

SELECT  *
    FROM  
      ( SELECT  ...  ORDER BY ... )
    GROUP BY ...

您希望内部查询中每组中的第一个(或最后一个)。问题是 SQL 可以随意优化掉这种意图。

文档中的分组最大代码效率非常低。

为了加快查询速度,可能的一点帮助是隔离Rules or PlacesWHERE 子句的一部分,并将其放入子查询中,该子查询仅返回相应表的 PRIMARY KEY。然后将其放入所有表的 JOIN 中(包括返回同一个表的 JOIN)。您已经拥有该子查询的“覆盖索引”,因此它可以是“使用索引”(用 EXPLAIN 使用的术语来说)。

innodb_buffer_pool_size 是否设置为可用 RAM 的 70% 左右?

BIGINT 占用 8 个字节;您可能可以接受 MEDIUMINT UNSIGNED (0..16M)。更小 --> 更可缓存 --> 更少的 I/O --> 更快。

lat/lng 的一对 DOUBLE 占用 16 个字节。一个 FLOAT 对将占用 8 个字节并具有 6 英尺/2m 分辨率。或者 DECIMAL(6,4) 表示纬度,(7,4) 表示经度,分别为 7 个字节和 52 英尺/16m 分辨率。对于“商店”来说已经足够好了,特别是因为您使用“正方形”而不是“圆形”来表示距离。

“查找最近的...”的代码很难优化。这是我想出的最好的:http://mysql.rjweb.org/doc.php/latlng http://mysql.rjweb.org/doc.php/latlng

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mysql存储函数和分组最小值[关闭] 的相关文章