- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
需要有关我的用例的数据模型的建议。我有两个参数要存储,A 用于 T 类型的东西,B 用于 U 类型的东西(它是 T 的集合)假设每个 T 类型的对象都有 2 个属性 p1 和 p2,现在A= (t 与 p1 的计数)/(t 与 p1 的计数)+(t 与 p1 的计数)
B= (A1+A2+.. ) 表示它的 T's 集合/(U 中 T's 的数量)。
现在,每当添加/修改 T 类型的新对象时,我都必须处理 A 和 B 的存储和更新问题。(几乎立即)
我决定按如下方式处理 A 的计算,以维护一个类似 (T id, No. of p1, No. of p2) 的表,因此每次数字变化时我只更新第 2 列或第 3 列并且 i可以即时计算 A。但我对如何优化 B 的计算感到困惑?我最初的想法是在上面的表格上写一个触发器,这样每当有东西更新时,就为那个 U 对象重新计算 B,但我认为当我扩大规模时,这会给我带来非常糟糕的性能,有什么建议我还可以在这里做什么?
示例:假设 U 是一个有许多街区 (T) 的城市。现在,每个街区都会有 p1 数量的非蔬菜餐厅和 p2 数量的蔬菜。因此,每个 block 的 A 为 p1/(p1+p2)每个城市的 B 将是该城市的 A1+A2+../count(blocks)。我如何为所有对象存储最初计算的 A 和 B,这样当 p1 和 p2 不断变化时,我几乎需要立即更新 A 和 B。
添加指标,以更清楚地了解所需的解决方案,
延迟应该是 ~100ms,即 A 和 B 在 p1/p2 更改后应该可用。
写入频率会出现峰值,会是 100 或 1000同时写入或 3-5 个。
最佳答案
使用您的城市/街区示例,您的架构可能类似于:
CREATE TABLE cities (
`city_id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`country_id` TINYINT UNSIGNED NOT NULL,
`zip` VARCHAR(50) NOT NULL,
`name` VARCHAR(100) NOT NULL,
PRIMARY KEY (`city_id`)
);
CREATE TABLE blocks (
`block_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
`city_id` SMALLINT UNSIGNED NOT NULL,
`p1` SMALLINT UNSIGNED NOT NULL DEFAULT '0',
`p2` SMALLINT UNSIGNED NOT NULL DEFAULT '1',
PRIMARY KEY (`block_id`),
FOREIGN KEY (`city_id`) REFERENCES `cities` (`city_id`)
);
您对给定城市 (city_id = 123
) 的查询将是:
查询 1
SELECT AVG(p1/(p1+p2)) AS B
FROM blocks b
WHERE b.city_id = 123
注意:AVG(x) = SUM(x)/COUNT(x)
现在,如果您担心性能,您应该定义一些预期的数字:
如果您已经定义了这些数字,您可以生成一些虚拟/假数据来对其运行性能测试。
这是一个包含 1000 个城市和 100K 个街区的示例(平均每个城市 100 个街区):
首先创建一个包含 100K 序列号的帮助表:
CREATE TABLE IF NOT EXISTS seq100k
SELECT NULL AS seq
FROM information_schema.COLUMNS c1
JOIN information_schema.COLUMNS c2
JOIN information_schema.COLUMNS c3
LIMIT 100000;
ALTER TABLE seq100k CHANGE COLUMN seq seq MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY;
对于 MariaDB,您可以改用序列插件。
生成数据:
DROP TABLE IF EXISTS blocks;
DROP TABLE IF EXISTS cities;
CREATE TABLE cities (
`city_id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`country_id` TINYINT UNSIGNED NOT NULL,
`zip` VARCHAR(50) NOT NULL,
`name` VARCHAR(100) NOT NULL,
PRIMARY KEY (`city_id`)
)
SELECT seq AS city_id
, floor(rand(1)*10+1) as country_id
, floor(rand(2)*99999+1) as zip
, rand(3) as name
FROM seq100k
LIMIT 1000;
CREATE TABLE blocks (
`block_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
`city_id` SMALLINT UNSIGNED NOT NULL,
`p1` SMALLINT UNSIGNED NOT NULL DEFAULT '0',
`p2` SMALLINT UNSIGNED NOT NULL DEFAULT '1',
PRIMARY KEY (`block_id`),
FOREIGN KEY (`city_id`) REFERENCES `cities` (`city_id`)
)
SELECT seq AS block_id
, floor(rand(4)*1000+1) as city_id
, floor(rand(5)*11) as p1
, floor(rand(6)*20+1) as p2
FROM seq100k
LIMIT 100000;
现在您可以运行查询了。请注意,我不会使用确切的运行时间。如果您需要它们准确无误,则应使用分析。
运行查询 1 我的 GUI (HeidiSQL) 显示 0.000 秒
,我称之为“几乎即时”。
您可能想要运行如下查询:
查询 2
SELECT b.city_id, AVG(p1/(p1+p2)) AS B
FROM blocks b
GROUP BY b.city_id
ORDER BY B DESC
LIMIT 10
HeidiSQL 显示 0.078 秒
。
使用覆盖索引
ALTER TABLE `blocks`
DROP INDEX `city_id`,
ADD INDEX `city_id` (`city_id`, `p1`, `p2`);
您可以将运行时间减少到 0.031 秒
。如果这还不够快,您应该考虑一些缓存策略。一种方法(除了在应用程序级别缓存之外)是使用触发器来管理 cities
表中的新列(我们就称它为 B
):
ALTER TABLE `cities` ADD COLUMN `B` FLOAT NULL DEFAULT NULL AFTER `name`;
定义更新触发器:
DROP TRIGGER IF EXISTS `blocks_after_update`;
DELIMITER //
CREATE TRIGGER `blocks_after_update` AFTER UPDATE ON `blocks` FOR EACH ROW BEGIN
if new.p1 <> old.p1 or new.p2 <> old.p2 then
update cities c
set c.B = (
select avg(p1/(p1+p2))
from blocks b
where b.city_id = new.city_id
)
where c.city_id = new.city_id;
end if;
END//
DELIMITER ;
更新测试:
查询 3
UPDATE blocks b SET p2 = p2 + 100 WHERE 1=1;
UPDATE blocks b SET p2 = p2 - 100 WHERE 1=1;
此查询在没有触发器的情况下运行 2.500 秒
,在有触发器的情况下运行 60 秒
。这看起来可能有很多开销 - 但考虑一下,我们要更新 100K 行两次 - 这意味着平均 60K 毫秒/200K 更新 = 0.3 毫秒/更新
。
现在您可以使用 查询 2 获得相同的结果
查询 4
SELECT c.city_id, c.B
FROM cities c
ORDER BY c.B DESC
LIMIT 10
“几乎立即”(0.000 秒
)。
如果需要,您仍然可以优化触发器。在 cities
表中使用附加列 block_count
(也需要使用触发器进行管理)。
添加列:
ALTER TABLE `cities`
ADD COLUMN `block_count` MEDIUMINT UNSIGNED NOT NULL DEFAULT '0' AFTER `B`;
初始化数据:
UPDATE cities c SET c.block_count = (
SELECT COUNT(*)
FROM blocks b
WHERE b.city_id = c.city_id
)
WHERE 1=1;
重写触发器:
DROP TRIGGER IF EXISTS `blocks_after_update`;
DELIMITER //
CREATE TRIGGER `blocks_after_update` AFTER UPDATE ON `blocks` FOR EACH ROW BEGIN
declare old_A, new_A double;
if new.p1 <> old.p1 or new.p2 <> old.p2 then
set old_A = old.p1/(old.p1+old.p2);
set new_A = new.p1/(new.p1+new.p2);
update cities c
set c.B = (c.B * c.block_count - old_A + new_A) / c.block_count
where c.city_id = new.city_id;
end if;
END//
DELIMITER ;
有了这个触发器,查询 3 现在可以在 8.5 秒
内运行。这意味着每次更新的开销为 0.03 毫秒
。
请注意,您还需要定义 INSERT 和 DELETE 触发器。并且您将需要添加更多逻辑(例如,处理更新时 city_id
中的更改)。但也有可能您根本不需要任何触发器。
关于mysql - 需要数据模型方面的建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43849442/
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!