如何加快drupal的node_save()函数?


9

node_save()的效率低下给我带来很多麻烦。但是节点可以解决我的问题吗?最终,这就是我想要找出的。

我创建了一个具有100,000次迭代的循环。我创建了使节点对象有效并正确保存的最低要求。这是节点保存代码:

$node = new stdClass();
        $node->type = "test_page";

        node_object_prepare($node);

        $node->uid = 1;
        $node->title = $node_title;
        $node->status = 1;
        $node->language = LANGUAGE_NONE;
        if($node = node_submit($node)){
            node_save($node);
}

结果如下:

保存了100,000个节点,每个节点都使用node_save()。完成了5196.22秒。那就是19节省一秒钟。

至少可以说,这是不可接受的,特别是当此人每秒获得大约1200个单独的插入查询,并且这个人每秒获得25,000个插入时

那么,这是怎么回事?瓶颈在哪里?是否与node_save()函数一起使用以及如何设计?

可能是我的硬件吗?我的硬件是一台开发服务器,除我之外没有人可以使用-Intel双核,3Ghz,Ubuntu 12.04和16 gig的ram。

在循环运行时,我的资源使用情况是:MySQL 27%CPU,6M RAM;PHP 22%CPU 2M RAM。

我的mysql配置由percona向导完成

Mysql说,如果我的CPU使用率低于70%,我的问题就是磁盘绑定。当然,我只有WD Caviar 7200 RPM磨粉机,但我希望它每秒能获得超过19次插入!

不久之前,我写过关于每天节省30,000个节点的文章。但是,需要明确的是,该节点与任何外力无关。纯粹是了解如何提高对node_save()的调用速度的基准。

实际上,我需要使用node_save每分钟将30,000个项目放入数据库。如果不选择保存节点,我想知道我是否可以编写自己的drupal api函数“ node_batch_save()”或利用mysql的INSERT查询功能进行批量插入的功能。关于如何处理此问题的想法?


2
原始插入性能和node_save将执行的操作之间存在很大差异。一方面,node_save执行一系列读取和写入。但是没有更多的数据讨论可能的瓶颈和优化毫无意义。
Alfred Armstrong

您需要考虑为什么出于您的目的使用这种方式的Drupal。如果你只是想捕捉到大量的数据在一个平坦的桌面,并使用Drupal的显示出来,你可能会写,当它想绕过Drupal的完全和使用自定义模块使用意见等,以数据集成
阿尔弗雷德·阿姆斯特朗

我怀疑瓶颈在数据库方面。节点保存在后台做了很多事情:它将调用许多挂钩(hook_node_presave,hook_entity_presave,hook_node_insert,hook_entity_insert等),每个挂钩都可以调用任意数量的模块。此外,node_save将重建该节点的权限,并将清除该节点的缓存...
爱丽丝·希顿2013年

@AlfredArmstrong我正在基于另一个数据库中的数据创建节点。我将数据塑造为正确的drupal内容类型并保存它。我的客户主要是想换成Drupal的大学。在使用了自己的Web解决方案十年后,他们希望迁移200,000到1,000,000个节点(部门的站点内容,学生和教职员工记录等)并不少见。我读了这篇文章,这是令人鼓舞的,但仍然不尽人意。evolvingweb.ca/story/...
blue928

..所以,我宁愿尽可能地保持精神状态。使用节点保存的大量数据可确保完整性。如果我无法解决这个问题,那么我愿意发挥创造力。
blue928 2013年

Answers:


10

使用node_save不会在一分钟内得到3万次插入。没门。

INSERT很快,因为这就是全部。节点保存执行多次插入(主表,修订表,每个字段的表),清除所有实体缓存并触发钩子。钩子是棘手的部分。如果您有很多contrib模块(甚至是行为不当的模块)确实可以破坏性能,尤其是在作者没有考虑“我一次节省大量节点”的用例的情况下。例如,我必须将其添加到我的Migrate类中:

  public function processImport(array $options = array()) {
    parent::processImport($options = array());
    // Do not force menu rebuilding. Otherwise pathauto will try to rebuild
    // in each node_save() invocation.
    variable_set('menu_rebuild_needed', FALSE);
  }

另一方面,如果编写一个不调用任何钩子的自定义保存函数,则很可能会在系统无法预料的状态下获取不一致的数据。我永远不建议这样做。启动xhprof,看看发生了什么。


那里有一些迁移模块,它们如何最终成为批量节省节点?我的意思是,所有这些都归结为一个INSERT语句,对吗?当不使用节点保存但仍需要维护表之间的数据完整性时,迁移类最终如何从“源”插入到“目标”?
blue928

我遇到的所有迁移模块都使用node_save。
Alfred Armstrong

1
@ blue928他说他确实使用过node_save(),但是添加了一些代码来减轻可能引起的已知问题,例如Pathauto在保存每个节点后重建菜单缓存
Clive

啊,好的,我明白了。Bojan在模块或在线中提供您的代码,在那里我可以看到您如何处理路径自动之类的瓶颈?xhprof的好主意。我会检查一下。
blue928 2013年

5

首先,安装XCache / APC(对于PHP <5.5)并为Drupal配置memcached。

然后,可以使用http://mysqltuner.pl上提供的mysqltuner脚本优化针对大量查询的MySQL配置。

例如

# performance tweaks (adjusted based on mysqltuner.pl)
query_cache_size = 32M
query_cache_limit = 256M
join_buffer_size = 32M
key_buffer = 8M
max_allowed_packet = 32M
table_cache = 512
sort_buffer_size = 1M
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 1M
myisam_sort_buffer_size = 8M

# When making adjustments, make tmp_table_size/max_heap_table_size equal
tmp_table_size = 16M
max_heap_table_size = 16M

thread_cache_size = 4

其他建议:

  • 禁用不需要的模块(例如,Devel,核心数据库日志记录模块等),
  • 将您的PHP升级到最新版本或更高版本,
  • 根据您的CPU重新为64位或更高版本的体系结构编译PHP,
  • 为您的db文件或整个LAMP环境(例如SSD或基于内存的文件系统)使用速度更快的存储设备,
  • 使用PHP调试器或探查器找出任何性能瓶颈(例如XDebug ProfilerDTraceNuSphere PhpED PHP Profiler),
  • gprof分析工具下运行一些耗时的drush命令,因此您也可以找到一些性能瓶颈

1
调整MySQL似乎有很大的不同。仅仅按照mysqltuner.pl给出的提示,我从大约80分钟的node_saves节省到了700分钟。
John McCollum 2014年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.