Exporting Org-Mode Documents With Many Org-Id Links Is Slow

Exporting org-mode documents using ox is very slow when there are many org-id links in the contents.

After some profiling I found the following code is called during export in a loop over each org-id link which returns the link’s file location.

(car (org-id-find id))

Unfortunately, org-id-find will load the file and all of it’s associated modes. This is very slow when all it needs is the file location.

Replacing it with the following makes the code roughly 10x faster.

(org-id-find-id-file id)

As a temporary workaround, you can overwrite org-export--collect-tree-properties:

(eval-after-load "ox"
  ;; Org export is very slow when processing org-id links. Override it
  ;; to skip opening the file and loading all modes.
  (defun org-export--collect-tree-properties (data info)
    "Extract tree properties from parse tree.

    DATA is the parse tree from which information is retrieved.  INFO
    is a list holding export options.

    Following tree properties are set or updated:

    `:headline-offset' Offset between true level of headlines and
                       local level.  An offset of -1 means a headline
                       of level 2 should be considered as a level
                       1 headline in the context.

    `:headline-numbering' Alist of all headlines as key and the
                          associated numbering as value.

    `:id-alist' Alist of all ID references as key and associated file
                as value.

    Return updated plist."
    ;; Install the parse tree in the communication channel.
    (setq info (plist-put info :parse-tree data))
    ;; Compute `:headline-offset' in order to be able to use
    ;; `org-export-get-relative-level'.
    (setq info
          (plist-put info
                     (- 1 (org-export--get-min-level data info))))
    ;; From now on, properties order doesn't matter: get the rest of the
    ;; tree properties.
     (list :headline-numbering (org-export--collect-headline-numbering data info)
           (org-element-map data 'link
             (lambda (l)
               (and (string= (org-element-property :type l) "id")
                    (let* ((id (org-element-property :path l))
                           (file (org-id-find-id-file id)))
                      (and file (cons id (file-relative-name file))))))))))

See also: