My application uses quite long and complex query, and profiling showed that slowest function is SQL-COMPILE. First I reimplemented it with S-SQL::STRCAT, but then I thought: what if it will hit CALL-ARGUMENTS-LIMIT (it is only 4096 on GNU Clisp!)? So I changed implementation of S-SQL:STRCAT to get list as the only argument, not as &rest.
SQL-COMPILE is much faster and consumes on my query 10 times less memory. As SQL-COMPILE is usually called on run time, not compilation time, I think it is very important.
--- old/s-sql/s-sql.lisp~ 2008-01-07 20:05:17.000000000 +0600 +++ new/s-sql/s-sql.lisp 2008-01-07 23:26:03.000000000 +0600 @@ -25,7 +25,7 @@
;; Utils
-(defun strcat (&rest args) +(defun strcat (args) "Concatenate a list of strings into a single one." (let ((result (make-string (reduce #'+ args :initial-value 0 :key 'length)))) (loop :for pos = 0 :then (+ pos (length arg)) @@ -36,11 +36,11 @@ (defun implode (sep list) "Reduce a list of strings to a single string, inserting a separator between them." - (apply 'strcat - (loop :for element :on list - :collect (car element) - :if (cdr element) - :collect sep))) + (strcat + (loop :for element :on list + :collect (car element) + :if (cdr element) + :collect sep)))
(defun split-on-keywords% (shape list) "Helper function for split-on-keywords. Extracts the values @@ -338,11 +338,11 @@ (let ((list (reduce-strings (sql-expand form)))) (if (= 1 (length list)) (car list) - `(strcat ,@list)))) + `(strcat (list ,@list)))))
(defun sql-compile (form) (let ((*expand-runtime* t)) - (car (reduce-strings (sql-expand form))))) + (strcat (sql-expand form))))
;; The reader syntax.
@@ -378,7 +378,7 @@ (declare (type (member t :both nil) class)) (cond ((cdr args) - `("(" ,@(sql-expand-list args (strcat " " operator " ")) ")")) + `("(" ,@(sql-expand-list args (strcat (list " " operator " "))) ")")) ((eq class t) (sql-expand (first args))) ((eq class :both)