|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
Доброго всем! Есть приложение. Один из шагов, это раздробить огромный файл CSV и залить в оракловую таблицу. Делать нужно максимально быстро, поэтому читаю файл в несколько потоков (каждый поток читает свою часть строк с N до M). Формирую через StringBuilder по 1000 строк такие простыни: Код: plsql 1. 2. 3. 4. 5. 6.
и далее скармливаю методу-обёртке с доп. логикой. Для простоты перепишем код в таком виде: Код: vbnet 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
Всё красиво работает и замечательно... но плохо то, что приложение сжирает 500 мб памяти сейчас и она не освобождается. Сборка GC не помогает, значит ссылка где-то есть. При том, как видим в коде всё вычищается, объекты диспозятся. Далее, смотрим в профайлере куда это девается. Оказывается есть внутренний класс типа Oracle.DataAccess.Client.Pooler, который инициализируется для переменной Oracle.DataAccess.Client.UTF8CommandText.m_pooler так: Код: c# 1.
Он хранит до 200 последних текстов команд, они сортируются по частоте использования и ещё какая-то логика (подсмотрел через IL Spy). Похоже из-за static она внутри методов не чистится и не предполагалось, что в неё начнут пихать столько много запросов. Может быть кто имел дело с этой библиотекой и возникала похожая проблема? Либо есть методы для чистки пула комманд (не путать с пуллом коннектов) Переписывать параметрические запросы в данном случае не подойдёт. Т.к. это очень медленно. Либо у меня не завелось. Либо как-то сказать драйверу ODAC чтобы он открыл транзакцию и когда выполняю .ExecuteNonQuery() фактически нужно добавить в текущую транзакцию. Обрамлять в begin insert into t .... end; ещё не пробовал. Но не выполняя запрос в анонимном блоке, а прямо .CommandText = "insert into t ...." с подготовленными параметрами, всё равно работает медленно. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 15:09 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 16:29 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
carrotik, не хотелось бы внешние утилиты тащить ... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 16:30 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
VSVLAD carrotik, не хотелось бы внешние утилиты тащить https://www.c-sharpcorner.com/article/two-ways-to-insert-bulk-data-into-oracle-database-using-c-sharp/ ... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 17:32 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
VSVLAD, у вас совершенно отвратительный способ для вставки огромного массива данных ... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 17:33 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
+1 - hVostt Но феерия начинается чуть раньше "поэтому читаю файл в несколько потоков (каждый поток читает свою часть строк с N до M)" ... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 18:17 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
buser, если критикуешь, предлагай решение. Рабочее решение, с определёнными условиями ... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 18:46 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
VSVLAD buser, если критикуешь, предлагай решение. Рабочее решение, с определёнными условиями операция чтения из файла тут наименее затратная, можно просто почитать N строк, разбить и выполняться параллельно, а так еще не известно, + если длинная строки не фиксированная, нужно будет найти заданную строку, чтоб начать чтение с неё. Ну и как по мне, всё это имеет смысл только тогда, когда вставка идет параллельно в разные таблицы, тогда скорость возрастёт сильно. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 19:02 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
Roman Mejtes, Практически так и работает. Сначала считаем количество строк в файле. Эта операция на ~ 2.5 млн строк занимает где-то 1 секунду. Далее логически файл делим на сегменты и читает каждый таск (поток) свою часть строк, создаёт из них наборы инсертов и выполняет. Замерял, в многопоточном режиме, этот способ эффективнее, чем допустим читать файл в Parallel.ForEach или в одном потоке работать. Проблемы в скорости сейчас нет, заливка занимает около 15 минут в среднем. sqloader также чуточку быстрее работает, но не прям махом. А проблема в том, что память odac съел. Приложение запускается шедулером и работает примерно 3-4 часа, включая выполнение других шагов. На самом деле приложение это не совсем работает как типичное приложение. Это самописный продвинутый "блокнот" который читает файл скрипта на VB.NET, компилирует в сборку в памяти и исполняет "пользовательский" код. Сделано затем, чтобы обычные пользователи не программисты могли запускать свои скрипты, которые имеют продвинутый доступ к базам, сети, ftp через классы-обертки выполняющие задачу в 1 строку. Конкретно в этой задаче потребовалось грузить csv в базу, такова задача, помимо чтение его с sftp и далее после обработки, через soap выполняются определенные методы. Возможно т.к. библиотека в домене приложения и статик переменная не подчищена, то ссылка на неё всё ещё жива, пока приложение запущено. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.01.2020, 20:00 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
VSVLAD, VSVLAD Доброго всем! Есть приложение. Один из шагов, это раздробить огромный файл CSV и залить в оракловую таблицу. Делать нужно максимально быстро, поэтому читаю файл в несколько потоков (каждый поток читает свою часть строк с N до M). Формирую через StringBuilder по 1000 строк такие простыни: Код: plsql 1. 2. 3. 4. 5. 6.
Раз уж решили сами свой загрузчик писать, то будьте в курсе поговорки "row by row is slow by slow". В данном случае надо заполнять блоками фиксированного размера пакетированный экземпляр коллекции, а по достижении этого размера уже делать bulk-вставку в целевую таблицу через forall..insert. Фиксированного размера - чтобы не забить весь доступный UGA (или, еще хуже, выбрать свой лимит SGA, если пакет с прагмой SERIALLY_REUSABLE). Как-то так: Код: 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. 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.
Небольшой бенчмарк: Код: c# 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. 41. 42. 43. 44. 45. 46. 47.
Результат: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
Причина такой картины очень проста: 10 физических обращений к накопителю в случае BulkInsert, и 1000 физических обращений в случае DirectInsert. ... |
|||
:
Нравится:
Не нравится:
|
|||
11.01.2020, 11:22 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
VSVLAD А проблема в том, что память odac съел. Проблема не в этом. Вы сами генерируете конские тексты запросов. Какого, спрашивается? ... |
|||
:
Нравится:
Не нравится:
|
|||
11.01.2020, 11:45 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
hVostt, спасибо за ссылку, буду на работе, попробую использовать Oracle.DataAccess.Client.OracleBulkCopy ... |
|||
:
Нравится:
Не нравится:
|
|||
11.01.2020, 23:47 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
Сон Веры Павловны, спасибо за пример. Но я пошёл путём попроще, через класс OracleBulkCopy. Класс и память корретно освобождает и заливает 500К (42 Мб файл) за 5-6 секунд. Самый большой файл у меня 150 Мб пока Готовое решение на VB, кому интересно в спойлере. Код: vbnet 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. 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.
... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2020, 12:31 |
|
Oracle.DataAccess.Client ест память класс Pooler
|
|||
---|---|---|---|
#18+
+ Сама процедура. Забыл про неё Код: vbnet 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2020, 14:47 |
|
|
start [/forum/topic.php?fid=20&fpage=13&tid=1398651]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
71ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
46ms |
get tp. blocked users: |
1ms |
others: | 243ms |
total: | 405ms |
0 / 0 |