我有大量数据,并且在1个请求期间我实例化了Time
30_000次。我已经检查了性能并发现从db查询数据需要0.020秒并使用
Time.zone.at(seconds_with_fraction)
花了0.5秒。
我已经对Time.zone.at
和Time.at
之间的差异进行了基准测试,得到了:
puts Benchmark.measure { 30_000.times { Time.zone.at(1439135459.6) } }
0.510000 0.010000 0.520000 ( 0.519298)
和
puts Benchmark.measure { 30_000.times { Time.at(1439135459.6) } }
0.060000 0.000000 0.060000 ( 0.068141)
有没有办法减少需要Time类在UTC区域中实例化对象的时间?
答案 0 :(得分:3)
这不仅仅是时区变化需要很长时间。如果你只是使用$escorts = [];
$newResults = [];
$escortMap = [];
foreach($escorts as $escortId => $e){
$escortMap[$e->Escort->id][] = $escortId;
}
foreach( $patients as $patientId => $p ){
$newResults[] = array(
'type' => 'patient',
'rec' => $p
);
foreach( $escortMap[$patientId] as $escortId){
$e = $escorts[$escortId];
if($e->Escort->id == $patient->Guest->id){ // or some other test to see if this escort matches this patient
$newResults[] = array(
'type' => 'escort for ' . $patientId,
'rec' => $e
);
}
}
}
,你就不会看到同样的减速:
Time.now
解决问题的最佳方法是使用与提供自unix时代以来的秒数不同的方法来定义irb(main):022:0> puts Benchmark.measure { 30_000.times { Time.now } }
0.030000 0.000000 0.030000 ( 0.028038)
=> nil
irb(main):023:0> puts Benchmark.measure { 30_000.times { Time.now.utc } }
0.040000 0.010000 0.050000 ( 0.076438)
=> nil
。但是,如果您无法解决这个问题,那么使用Time
会更快一些,例如:
DateTime
答案 1 :(得分:1)
由于您尝试解决时间戳问题的方式,因此存在性能问题。通过另一种方式处理您的时间戳转换,您将获得良好的服务。
您的帖子无法解释您从哪里获取时区信息。因此,您不清楚为什么(或如何)实际处理时区。毫无疑问,有许多方法可以避免进行时区体操,但它们超出了您发布的代码的范围。尽管如此,本文中的最后一个示例显示了一种将会话时区附加到查询结果中每一行的方法。
关于你的Ruby on Rails速度问题,你并没有真正实例化Time,你实际上是从ActiveSupport :: TimeZone :: ThreadSafe实例化ActiveSupport::TimeZone,两者都是ActiveSupport和线程安全库必然会严重影响性能。您不能让Ruby更快地实例化对象,但是您可以通过使用数据库来执行转换来避免让自己头疼。
此外,虽然SQL-99和PostgreSQL将时区的时间戳定义为实际列类型,但MySQL和MariaDB都没有。因此,您真的不清楚计划如何存储转换后的数据,但您可能需要重新考虑速度和数据类型处理的方法。
无论你真正想做什么,几乎在每种情况下,正确的答案是将更多的工作从Rails推送到数据库中。一些MySQL / MariaDB示例如下所示。
您可以简单地将数据作为epoch-seconds传递到MySQL或MariaDB,并让数据库使用FROM_UNIXTIME函数为您执行转换,而不是尝试在Ruby中进行转换。例如:
> SELECT FROM_UNIXTIME(1439135459.6);
+-----------------------------+
| FROM_UNIXTIME(1439135459.6) |
+-----------------------------+
| 2015-08-09 10:50:59.6 |
+-----------------------------+
1 row in set (0.00 sec)
由您决定是将时间秒存储为数字还是时间戳,以及是否在存储或检索时转换数据。答案可能更多地取决于您计划如何搜索和加入您的数据,因此您的里程会有所不同。
如果您只想使用单个时区并将其附加到时间戳,那么如果您使用系统或会话时区,这将是微不足道的。例如:
> SELECT CONCAT(FROM_UNIXTIME(1439135459.6), " ", @@session.time_zone);
+---------------------------------------------------------------+
| CONCAT(FROM_UNIXTIME(1439135459.6), " ", @@session.time_zone) |
+---------------------------------------------------------------+
| 2015-08-09 10:50:59.6 -05:00 |
+---------------------------------------------------------------+
1 row in set (0.00 sec)
如果您想要执行更复杂的操作,则需要首先确保在计划使用区域名称而不是数字偏移时填充时区表。有关详细信息,请参阅mysql_tzinfo_to_sql。
无论您使用命名区域还是数字偏移,请在参数上调用CONVERT_TZ。例如:
> SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00');
+-----------------------------------------------------+
| CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00') |
+-----------------------------------------------------+
| 2004-01-01 22:00:00 |
+-----------------------------------------------------+
1 row in set (0.02 sec)
以下适用于MariaDB,并使用MariaDB的方便sequence engine来避免必须填充序列表或实际输入任何值以使示例工作。但是,MySQL的原理(以及速度提升!)应该是相似的,但是你实际上必须先麻烦地将epoch-seconds或timestamp数据加载到表中。
-- Set a session time zone to concatenate with query results.
SET time_zone = '-5:00';
-- Load sequence engine on MariaDB.
-- Skip on MySQL, which does not currently have a sequence engine.
INSTALL SONAME "ha_sequence";
-- Select from the sequence on MariaDB.
-- Change query to SELECT...FROM a table on MySQL.
SELECT CONCAT(
FROM_UNIXTIME(seq), @@session.time_zone
) FROM seq_1439135459_to_1439165458;
这返回了一个集合如下:
+---------------------------------------------------------------+
| CONCAT( FROM_UNIXTIME(seq), @@session.time_zone ) |
+---------------------------------------------------------------+
| 2015-08-09 10:50:59-05:00 |
| 2015-08-09 10:51:00-05:00 |
| 2015-08-09 10:51:01-05:00 |
| ... |
| 2015-08-09 19:10:57-05:00 |
| 2015-08-09 19:10:58-05:00 |
+---------------------------------------------------------------+
30000 rows in set (0.02 sec)
在我最老,最慢的笔记本电脑上,它在0.02秒或更短的时间内返回30,000行。服务器级硬件应该几乎不会注意到查询,但当然您的里程可能会有所不同。