- Только сейчас мы реализовали небольшую функцию в генераторе кода jOOQ: https://github.com/jOOQ/jOOQ/issues/4974.
Он обнаруживает всякий раз, когда генератор кода jOOQ выполняет медленный запрос для обратного инжиниринга метаинформации схемы. Почему?
В нашей тестовой среде для разработки и интеграции у нас нет огромных схем с различными вариантами производительности. Например, у нас нет 5000 синонимов Oracle. Или 10000 процедур с 500 параметрами в каждой. Мы рассмотрим некоторые общие крайние случаи, но не во всех базах данных.
С другой стороны, пользователи склонны принимать статус-кво через некоторое время. Генератор кода работает медленно? Конечно, потому что у нас огромная схема. Это ленивое признание является препятствием для качества нашей продукции. Скорее, наши пользователи сообщают о всевозможных проблемах, с которыми они сталкиваются, поэтому мы хотим их поощрять
И мы сделали
В следующей версии jOOQ 3.8 (и выпусках патчей для 3.5.5, 3.6.5 и 3.7.3) мы добавили в jOOQ-meta симпатичный маленький ExecuteListener , который выглядит примерно так:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
class PerformanceListener extends DefaultExecuteListener { StopWatch watch; class SQLPerformanceWarning extends Exception {} @Override public void executeStart(ExecuteContext ctx) { super.executeStart(ctx); watch = new StopWatch(); } @Override public void executeEnd(ExecuteContext ctx) { super.executeEnd(ctx); if (watch.split() > 5 * 1000 * 1000 * 1000) log.warn( "Slow SQL", "jOOQ Meta executed a slow query" + "\n\n" + "Please report this bug here: " + formatted(ctx.query()), new SQLPerformanceWarning()); }} |
Это очень просто. Каждый раз, когда мы начинаем выполнять запрос, запускается «секундомер». Каждый раз, когда мы заканчиваем выполнение, мы проверяем, прошло ли время больше 5 секунд. Если это так, мы регистрируем предупреждение, ссылку на наш трекер ошибок, отформатированную версию запроса SQL и трассировку стека, чтобы помочь найти точное место, где выполнялся медленный оператор.
Давайте запустим это
Причина, по которой мы это сделали, заключается в том, что мы сами убедились, что генератор кода PostgreSQL выполняет медленный запрос для извлечения всех хранимых процедур (и для генерации индексов перегрузки). Полученное сообщение об ошибке:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
[WARNING] Slow SQL : jOOQ Meta executed a slow query (slower than 5 seconds)Please report this bug here: https://github.com/jOOQ/jOOQ/issues/newselect "r1"."routine_schema", "r1"."routine_name", "r1"."specific_name", case when exists ( select 1 as "one" from "information_schema"."parameters" where ( "information_schema"."parameters"."specific_schema" = "r1"."specific_schema" and "information_schema"."parameters"."specific_name" = "r1"."specific_name" and upper("information_schema"."parameters"."parameter_mode") 'IN' ) ) then 'void' else "r1"."data_type" end as "data_type", "r1"."character_maximum_length", "r1"."numeric_precision", "r1"."numeric_scale", "r1"."type_udt_schema", "r1"."type_udt_name", case when exists ( select 1 as "one" from "information_schema"."routines" as "r2" where ( "r2"."routine_schema" in ( 'public', 'multi_schema', 'pg_catalog' ) and "r2"."routine_schema" = "r1"."routine_schema" and "r2"."routine_name" = "r1"."routine_name" and "r2"."specific_name" "r1"."specific_name" ) ) then ( select count(*) from "information_schema"."routines" as "r2" where ( "r2"."routine_schema" in ( 'public', 'multi_schema', 'pg_catalog' ) and "r2"."routine_schema" = "r1"."routine_schema" and "r2"."routine_name" = "r1"."routine_name" and "r2"."specific_name" <= "r1"."specific_name" ) ) end as "overload", "pg_catalog"."pg_proc"."proisagg"from "information_schema"."routines" as "r1" join "pg_catalog"."pg_namespace" on "pg_catalog"."pg_namespace"."nspname" = "r1"."specific_schema" join "pg_catalog"."pg_proc" on ( "pg_catalog"."pg_proc"."pronamespace" = "pg_catalog"."pg_namespace".oid and (("pg_catalog"."pg_proc"."proname" || '_') || cast("pg_catalog"."pg_proc".oid as varchar)) = "r1"."specific_name" )where ( "r1"."routine_schema" in ( 'public', 'multi_schema', 'pg_catalog' ) and not("pg_catalog"."pg_proc"."proretset"))order by "r1"."routine_schema" asc, "r1"."routine_name" asc, "overload" ascorg.jooq.util.AbstractDatabase$1$SQLPerformanceWarning at org.jooq.util.AbstractDatabase$1.executeEnd(AbstractDatabase.java:230) at org.jooq.impl.ExecuteListeners.executeEnd(ExecuteListeners.java:163) at org.jooq.impl.AbstractResultQuery.execute(AbstractResultQuery.java:269) at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:346) at org.jooq.impl.AbstractResultQuery.fetch(AbstractResultQuery.java:308) at org.jooq.impl.SelectImpl.fetch(SelectImpl.java:2703) at org.jooq.util.postgres.PostgresDatabase.getRoutines0(PostgresDatabase.java:707) at org.jooq.util.AbstractDatabase.getRoutines(AbstractDatabase.java:1131) at org.jooq.util.JavaGenerator.generate(JavaGenerator.java:417) at org.jooq.util.JavaGenerator.generate(JavaGenerator.java:314) at org.jooq.util.JavaGenerator.generate(JavaGenerator.java:279) at org.jooq.util.GenerationTool.run(GenerationTool.java:490) at org.jooq.util.GenerationTool.generate(GenerationTool.java:193) at org.jooq.util.maven.Plugin.execute(Plugin.java:131) ... |
Теперь мы можем легко приступить к исправлению запроса.
Вы можете сделать то же самое!
Реализация ExecuteListener была прямой. Вы можете сделать то же самое, очень легко. Просто подключите простой слушатель выполнения к вашей Configuration jOOQ, измеряя скорости выполнения и регистрируя предупреждения после определенного порога.
Удачной отладки!
дальнейшее чтение
По совпадению, очень похожий подход был задокументирован командой инженеров Square — The Query Sniper: https://corner.squareup.com/2016/01/query-sniper.html.
| Ссылка: | Как обнаружить медленные запросы с помощью jOOQ от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и JOOQ . |