|
sql вместо циклов
|
|||
---|---|---|---|
#18+
Друзья, подскажите пожалуйста как оптимизировать такую задачу. Есть таблица с полем VARCHAR2 и двумя полями типа VARRAY. В первом поле храниться имя, во втором - 512 исходных значений, в третье поле записываю результат функции. Функция делает преобразование Фурье и возвращает массив VARRAY. Такой подсчет идет по каждой строке. Строк очень много. Все работает и считает, но по причине использования циклов все это работает очень медленно. Подскажите пожалуйста, возможно ли решить эту задачу SQLем (аналитическими функциями, конвеерными функциями)? В каком направлении копать? Вот пример данных Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.
В принципе я развернул данные без массива (varchar2 и number) и попробовал так, но опыта не хватает построить алгоритм подсчета Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
в функцию передаю поле VAL (массив) Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25.
... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 09:17 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow432, На вскидку: нормализовать, убратв varray, и добавив number(10,3). Это уберёт цикл. Двойной цикл получится в результате декартова произведения. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 09:48 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
crutchmaster, при таком раскладе получается на каждую строку из 512 записей декартово произведение дает 262144 записи. И я бы рад проверить такой алгоритм (скорее всего он будет работать быстрее), но я ума не приложу как мне прикрутить это декартово произведение к подсчетам Фурье l_val_re(k) := nvl(l_val_re(k), 0) + p_val_varr(n) * cos((2 * l_pi * (k - 1) * (n - 1)) / l_rows_cnt); ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 09:54 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow432 но я ума не приложу как мне прикрутить это декартово произведение к подсчетам Фурье Надо id массива, значение элемента, номер элемента, количество элементов. А потом связать таблицу саму с собой по id массива и посчитать. shadow432 дает 262144 записи Не прокатит - пили трехзвенку. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 10:01 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
crutchmaster, Такую структуру с массивом я выбрал сам для удобства и наглядности (это промежуточная временная таблица), но если использовать декартово произведение, то может имеет смысл сразу развернуть этот массив в общей таблице? Не понял что значит трехзвенка? Если развернуть так, тогда декартово произведение даст 262144 записей. A 1 A 4 A 8 ........ 512 строк ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 10:19 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow432 развернуть этот массив в общей таблице? Каким образом? shadow432 Не понял что значит трехзвенка? Вытащить данные из субд куда-нибудь (java/пистон/жс/c#/etc), посчитать, засунуть обратно. shadow432 Если развернуть так, тогда декартово произведение даст 262144 записей Да. Будет мегабайт 5-10 на запись. Херня, конечно, лучше сразу трехзвенка. Хотя, если это всё сразу сгрупировать или вставить, то должно быть норм. Но оверхед всё равно дикий. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 10:27 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
crutchmaster, Должно быть решение SQLем, BULK COLLECT/FORALLы. Просто нужно очень широкое видение возможностей ORACLE. Слишком большие объемы чтобы передавать во внешку. Не думаю что циклы в том же PYTONе будут работать гораздо быстрее. А с учетом передачи данных туда сюда... В любом случае, спасибо за помощь! Буду копать дальше. Может асы подскажут еще. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 10:38 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow432 Слишком большие объемы чтобы передавать во внешку. Передавай частями. shadow432 Не думаю что циклы в том же PYTONе будут работать гораздо быстрее. В питоне не будет. Во всём остальном - надо смотреть. shadow432 А с учетом передачи данных туда сюда... Если не по одной строчке, то тоже не должно быть особых тормозов в этом месте. Передаешь метров 100 сырых данных, считаешь, передаёшь обратно. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 10:52 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow432 Может асы подскажут еще Оракл-спецефичное может что и есть. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 10:53 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow432, Вы что каждый раз считаете? раз посчитать и результат сохранить 1) мож cos((2 * l_pi * (k - 1) * (n - 1)) / l_rows_cnt) sin((2 * l_pi * (k - 1) * (n - 1)) / l_rows_cnt) вычислить один раз и сохранить,а не для каждой строки 2) l_val_out(n) := sqrt(power(l_val_re(n), 2) + power(l_val_im(n), 2)); понять в for k 3) вместо l_val_out использовать re/im (p_val_varr сделать in/oit) ps врядли декартовое + группировка будут быстрее, хотя пробовать надо ..... stax ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 11:55 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
вдогонку делеть на l_rows_cnt можно за циклом sum(a(i)/n)=sum(a(i))/n ..... stax ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 12:00 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
што-то такое получилось Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 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.
..... stax ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 12:41 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
Stax, 1. Нельзя вычислить один раз потому что методика преобразования Фурье такая. Расчет ведется для каждой строки с участием каждой последующей. Может я туплю? Поправьте пожалуйста если так. 2. Поднял. Производительности не дало ни секунды. 3. Сделал IN OUT. Выигрыша в производительности нет. 4. Делить на cnt за циклом нельзя (п.1) Хотя опять же не исключаю что я что то не догоняю. Сейчас попробую с декартовым переварить. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 13:27 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow4321. Нельзя вычислить один раз потому что методика преобразования Фурье такая. Расчет ведется для каждой строки с участием каждой последующей. Может я туплю? Поправьте пожалуйста если так. cos((2 * l_pi * (k - 1) * (n - 1)) / l_rows_cnt) детерминировано для k, n, l_rows_cnt а т.к. у вас эти значения повторяются от вычисления к вычислению, то логично посчитать их один раз и при следующих вызовах функции обращаться к уже сохраненным значениям. Так же не очень хорошо что у вас вычисления идут с типом number, стоит от этого уйти и попробовать Native compilation. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 13:45 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow432 Stax, 1. Нельзя вычислить один раз потому что методика преобразования Фурье такая. Расчет ведется для каждой строки с участием каждой последующей. Может я туплю? Поправьте пожалуйста если так. 2. Поднял. Производительности не дало ни секунды. 3. Сделал IN OUT. Выигрыша в производительности нет. 4. Делить на cnt за циклом нельзя (п.1) Хотя опять же не исключаю что я что то не догоняю. Сейчас попробую с декартовым переварить. 1) раз посчитать для имени, пересчитивать токо когда поменяется (Вам виднее) 4) так нельзя? for k in 1 .. l_rows_cnt loop for n in 1 .. l_rows_cnt loop l_val_re(k) := nvl(l_val_re(k), 0) + p_val_varr(n) * cos((2 * l_pi * (k - 1) * (n - 1)) ; l_val_im(k) := nvl(l_val_im(k), 0) - p_val_varr(n) * sin((2 * l_pi * (k - 1) * (n - 1)) ; end loop; l_val_re(k) :=l_val_re(k) / l_rows_cnt; l_val_im(k) :=l_val_im(k)/ l_rows_cnt; end loop; ps ,(select sqrt( power(sum(t2.val*cos(2 *3.14 * (t.k - 1) * (t2.k - 1)))/count(*),2) -power(sum(t2.val*sin(2 *3.14 * (t.k - 1) * (t2.k - 1)))/count(*),2) ) проверте результат с пл/скл (мож как всегда что-то напутал) pss на sin/cos времени тратится немного? ..... stax ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 14:34 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
ln123, вычислить один раз и сохранить,а не для каждой строки ..... stax ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 14:37 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
ln123, Спасибо за ценное замечание. Поправил этот баг. В начале выполнения программы считаю отдельными циклами и засовываю эти значения в двумерный ассоциативный массив. Скорость выросла в 10 раз. Native compilation никогда не использовал. Где почитать про это? Нужны будут права SYS я так понимаю? ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 16:59 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
shadow432 Поправил этот баг. 1) мож cos((2 * l_pi * (k - 1) * (n - 1)) / l_rows_cnt) sin((2 * l_pi * (k - 1) * (n - 1)) / l_rows_cnt) вычислить один раз и сохранить,а не для каждой строки ..... stax ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 17:17 |
|
sql вместо циклов
|
|||
---|---|---|---|
#18+
Stax, по всей видимости именно расчет синусов и косинусов жрал большую часть времени. Вынес их расчет в двухмерный ассоциативный массив и код "задышал". Конечно, наверное можно еще оптимизировать, но такой результат для меня уже приемлем. Спасибо за помощь! ... |
|||
:
Нравится:
Не нравится:
|
|||
18.03.2020, 17:50 |
|
|
start [/forum/topic.php?fid=52&fpage=51&tid=1881448]: |
0ms |
get settings: |
11ms |
get forum list: |
13ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
34ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
55ms |
get tp. blocked users: |
2ms |
others: | 14ms |
total: | 152ms |
0 / 0 |