Типичная производительность в Slick (версия 3.1.1)

У меня есть следующий SQL-запрос:

select `sr_roleName`, `sr_id` from `db_security_role` where `sr_roleName` = 'admin'

Он генерируется из следующего кода Slick:

RoleTable.filter(_.name === roleName).result.head

Итак, это кажется довольно простым (на самом деле самое простое, что у вас может быть, верно?). Теперь давайте посмотрим на следующие результаты (журналы ниже):

[debug] s.c.QueryCompilerBenchmark - ------------------- Phase: Time ---------
[debug] s.c.QueryCompilerBenchmark -       assignUniqueSymbols:    0.257579 ms
[debug] s.c.QueryCompilerBenchmark -                inferTypes:    0.774230 ms
[debug] s.c.QueryCompilerBenchmark -              expandTables:   18.949290 ms
[debug] s.c.QueryCompilerBenchmark -           forceOuterBinds:    3.438698 ms
[debug] s.c.QueryCompilerBenchmark -         removeMappedTypes:    2.760705 ms
[debug] s.c.QueryCompilerBenchmark -                expandSums:    0.702326 ms
[debug] s.c.QueryCompilerBenchmark -         emulateOuterJoins:    1.025963 ms
[debug] s.c.QueryCompilerBenchmark -             expandRecords:    1.022323 ms
[debug] s.c.QueryCompilerBenchmark -        flattenProjections:   10.691557 ms
[debug] s.c.QueryCompilerBenchmark -              rewriteJoins:    0.790561 ms
[debug] s.c.QueryCompilerBenchmark -             verifySymbols:    4.421257 ms
[debug] s.c.QueryCompilerBenchmark -             relabelUnions:    1.511849 ms
[debug] s.c.QueryCompilerBenchmark -          createAggregates:    0.612787 ms
[debug] s.c.QueryCompilerBenchmark -           resolveZipJoins:    0.723972 ms
[debug] s.c.QueryCompilerBenchmark -          pruneProjections:    4.261886 ms
[debug] s.c.QueryCompilerBenchmark -           rewriteDistinct:    2.408857 ms
[debug] s.c.QueryCompilerBenchmark -    createResultSetMapping:    2.745822 ms
[debug] s.c.QueryCompilerBenchmark -            hoistClientOps:    7.755399 ms
[debug] s.c.QueryCompilerBenchmark -         reorderOperations:    1.650360 ms
[debug] s.c.QueryCompilerBenchmark -     mergeToComprehensions:   27.408578 ms
[debug] s.c.QueryCompilerBenchmark -            optimizeScalar:    1.784032 ms
[debug] s.c.QueryCompilerBenchmark -          removeFieldNames:   13.811206 ms
[debug] s.c.QueryCompilerBenchmark -                   codeGen:   20.328294 ms
[debug] s.c.QueryCompilerBenchmark -                     TOTAL:  129.837531 ms
[debug] s.j.J.statement - Preparing statement: select `sr_roleName`, `sr_id` from `db_security_role` where `sr_roleName` = 'admin'
[debug] s.j.J.benchmark - Execution of prepared statement took 425µs

Как вы можете видеть, фактические затраты на выполнение запроса (занимает время) около 425 мкс. Возможно - выполняется на локальной машине/локальной базе данных. Что, однако, для меня крайне странно, так это то, что все время подготовки запроса в сумме стоит 129,837531 мс (что в 300 раз превышает время фактического выполнения запроса).

Итак, в основном мой вопрос:

  • это типичная характеристика производительности Slick?

  • есть ли что-то очевидное, что я могу делать неправильно?

спасибо


person Paul Dolega    schedule 27.09.2016    source источник
comment
Вы, наверное, просто неправильно меряете. Для первого запуска компилятора запросов это выглядит совершенно нормально. После надлежащего прогрева JIT я ожидаю, что время компиляции на моем MacBookPro 2012 года составит однозначное число мс. Посмотрите CompilerBenchmark< /а>. В среднем по 53 запросам низкой и средней сложности я получаю 183 мс для первого запуска и только 14 мс после нескольких десятков запусков.   -  person szeiger    schedule 28.09.2016
comment
Да, разминка может иметь место на самом деле. Это имеет смысл - эти цифры получены в результате выполнения одиночного модульного теста.   -  person Paul Dolega    schedule 29.09.2016
comment
@szeiger Я думаю, что ваш комментарий должен быть настоящим ответом. Измерение было неправильным - я тестировал только один тест. Это именно так, как вы описали. Если вы подумаете о создании фактического ответа, я с радостью отмечу его как правильный.   -  person Paul Dolega    schedule 30.09.2016


Ответы (2)


Кажется разумным. Каждый раз, когда выполняется параметризованный запрос, slick должен будет его перекомпилировать. Этого можно избежать путем предварительной компиляции таких запросов. Например:

def findByRoleName(roleName: Rep[String]) = RoleTable.filter(_.name === roleName)

val findByRoleNameCompiled = Compiled(findByRoleName _)

val result = findByRoleNameCompiled("myRole").result.head

Теперь запрос будет скомпилирован только один раз, и вы должны заметить улучшение производительности. Это также работает для вставки, обновления и удаления. Подробнее см. Компилированные запросы в документации.

person Roman    schedule 28.09.2016
comment
Хорошо - я понимаю предварительно скомпилированный запрос. Здесь нет проблем - но действительно ли возможно (типично?), что компиляция запроса занимает так много времени (даже с таким простым запросом)? - person Paul Dolega; 28.09.2016
comment
Судя по коду, который вы показали, я не вижу в этом ничего плохого. Но снова просматривая результаты тестов, компиляция действительно занимает немного времени. Однако эти числа могут быть совершенно случайными, поскольку мы не знаем, как было выполнено измерение. Я бы предложил собрать еще несколько результатов тестов и посмотреть, займет ли это все еще много времени. См. github.com /slick/slick/blob/master/slick-testkit/src/test/scala/ для примера, как получить полезные числа. - person Roman; 28.09.2016

На самом деле правильный ответ находится в этом комментарии @szeiger: Типичная производительность в Slick (версия 3.1.1)

Большое время подготовки запроса просто вызвано тем, что JVM не прогревается. После многократного выполнения различных запросов последующие готовятся намного быстрее. Также стоит помнить о компиляции запросов, на которую указал @Roman (хотя на самом деле это не то, о чем вопрос по своей сути).

Эта цитата из @szeiger в упомянутом комментарии в основном является лучшим ответом на этот вопрос:

В среднем по 53 запросам низкой и средней сложности я получаю 183 мс для первого запуска и только 14 мс после нескольких десятков запусков.

person Paul Dolega    schedule 15.12.2016