views:

350

answers:

2

I'm building a MySql query that batch inserts 4096 records at once. The actual insert is quite fast but the bottleneck is generating the query. Any hints on optimizing this? The string generation is currently taking about 18 times longer than the query.

                    let builder = StringBuilder(524288)
                    Printf.bprintf builder
                        "
                         INSERT INTO %s
                             (`ID`,
                              `Tag`,
                              `Port`,
                              `Excess`,
                              `Return`,
                              `StartDate`,
                              `EndDate`
                              ) 
                          values "
                        x.evaluationstable

                    evaluations
                    |> Seq.iter(fun (e) ->
                        Printf.bprintf builder 
                            " (%d, '%s', '%s', %A, %A, %A, %A), "
                            e.ID
                            e.Tag
                            e.Port
                            e.Excess
                            e.Return
                            (e.StartDate.ToString(x.datetimeformat))
                            (e.EndDate.ToString(x.datetimeformat))
                    )
+2  A: 

I would try to avoid embedding the data directly into SQL to start with. Use a sequence of prepared statements with parameters, and set those parameters to the values (without formatting them). That's safer and is likely to be a lot more efficient.

Whether you can still do this in a batch rather than in several separate calls just within the same transaction, I'm not sure.

Jon Skeet
Thanks for the response. I'd originally converted this from a set of parameterized statements and got a huge perf increase with the direct multi-row insert. I might try a hybrid of the two, a much larger multi-row parameterized type.I'm fairly new to F# so I was interested in whether there is a more efficient way to do the string concat I'm trying here. I did find that the %A format is incredibly expensive and managed to nearly halve the execution time by not using them.
MikeW
Safer, yes. More efficient, no! The overhead of round-tripping to db for every statement will kill performance.
Robert Jeppesen
+6  A: 

Try using StringBuilder.AppendFormat instead of Printf.bprintf. When I made this change in my example of your question, I saw a huge performance increase (~80x).

evaluations
|> Seq.iter (fun (e) ->
    builder.AppendFormat(
        " ({0}, '{1}', '{2}', {3}, {4}, {5}, {6}), ",
        e.ID,
        e.Tag,
        e.Port,
        e.Excess,
        e.Return,
        (e.StartDate.ToString("MM/dd/yyyy")),
        (e.EndDate.ToString("MM/dd/yyyy"))
    ) |> ignore
)
Ray Vernagus
Nice. This worked very well, I'm seeing about a 10x total speed increase, but this includes opening the connection and running the query. Thanks!
MikeW