Гость
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / substring BLOBа медленно / 25 сообщений из 45, страница 1 из 2
05.02.2020, 09:40
    #39922621
zeon11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
В процедуру загружаю (через BLOB) достаточно большой текст (XML).
в процедуре произвожу "резку" текста по тегам, с последующей вставкой фрагментов в таблицу.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
  teg='ZAP';
  teg_begin='<'||teg||'>';
  teg_end  ='</'||teg||'>';
  teg_begin_len = char_length(teg)+2;
  teg_end_len = char_length(teg)+3;
  LEN = char_length(:body_zap);
  if (LEN = 0) then exit;
  POS = 1;
  while (POS <= LEN)
     do begin
         pos_begin=POSITION(teg_begin, :body_zap, pos);
         if (pos_begin=0) then leave;
         POS=POS_BEGIN+teg_begin_len;
         POS=POSITION(teg_end, :body_zap, pos)+teg_end_len;
         length_block=pos - pos_begin;
         strbody=substring(:body_zap from :pos_begin for :length_block);

    --          insert into ...........................;

        end



столкнулся с тем, что небольшие файлы (1-2 мб, 1000 - 1500 блоков) обрабатываются достаточно быстро 2-3 секунды,
однако при размере файлов в 35 мб 19200 блоков процедура просаживается в производительности без вставки, а только на цикл WHILE ... затрачивается более 40 минут.

FB 2.59, WIN 2003, сервер виртуальный, 4 ядра XEON 2.4 , памяти 8GB, подключение только моё
...
Рейтинг: 0 / 0
05.02.2020, 09:50
    #39922624
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
zeon11,

временные блобы перестают помещаться в страничном кеше и начинают сбрасываться на диск
...
Рейтинг: 0 / 0
05.02.2020, 09:52
    #39922625
crutchmaster
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
zeon11,

В чём смысл делать всё это именно на стороне FB?
...
Рейтинг: 0 / 0
05.02.2020, 09:54
    #39922626
zeon11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Симонов Денис
zeon11,

временные блобы перестают помещаться в страничном кеше и начинают сбрасываться на диск


Ок, понятно. Спасибо.
...
Рейтинг: 0 / 0
05.02.2020, 09:57
    #39922629
zeon11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
crutchmaster
zeon11,

В чём смысл делать всё это именно на стороне FB?


Если это можно делать на сервере, зачем это делать ещё где-то?
...
Рейтинг: 0 / 0
05.02.2020, 10:05
    #39922635
hvlad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Симонов Денис
zeon11,

временные блобы перестают помещаться в страничном кеше и начинают сбрасываться на диск
Это легко проверить - смотреть на рантайм статистику выполнения запроса (writes).
Если так, то попробовать увеличить кеш, пока writes не придут в норму.
...
Рейтинг: 0 / 0
05.02.2020, 10:09
    #39922641
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
zeon11,

потому что на клиенте будет быстрее, распарсить XML, подготовить запрос и сделать инсерт получившихся кусков
...
Рейтинг: 0 / 0
05.02.2020, 10:23
    #39922658
zeon11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Симонов Денис
zeon11,

потому что на клиенте будет быстрее, распарсить XML, подготовить запрос и сделать инсерт получившихся кусков


Да, наверное, придётся так и делать. Раньше с малыми файлами разбирал XML исключительно на сервере. XML разбирался на полтора десятка таблиц, и разбирать на сервере было удобно, всё под рукой, но сейчас появились файлы до 90 мб, и всё резко просело по скорости.
...
Рейтинг: 0 / 0
05.02.2020, 10:29
    #39922665
hvlad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
hvlad
Это легко проверить - смотреть на рантайм статистику выполнения запроса (writes).
Если так, то попробовать увеличить кеш, пока writes не придут в норму.
reads конечно, не writes
...
Рейтинг: 0 / 0
05.02.2020, 10:56
    #39922681
crutchmaster
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Симонов Денис
потому что на клиенте будет быстрее, распарсить XML, подготовить запрос и сделать инсерт получившихся кусков

Да, и нагрузка уйдёт туда же. У сервера ресурсы не резиновые.
...
Рейтинг: 0 / 0
05.02.2020, 15:30
    #39922952
Василий 2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
А через udf не вариант? Либо отдельной службой
...
Рейтинг: 0 / 0
05.02.2020, 15:36
    #39922961
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Василий 2А через udf не вариант?

нет конечно. UDF умеет возвращать только скалярный результат, т.е. набор данных из неё не вернуть.
Выполнять запросы в контексте текущего коннекта и транзакции там тоже нельзя.

В UDR (внешние ХП) можно и то и другое, но это в 3.0
...
Рейтинг: 0 / 0
05.02.2020, 18:29
    #39923066
zeon11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
crutchmaster
Симонов Денис
потому что на клиенте будет быстрее, распарсить XML, подготовить запрос и сделать инсерт получившихся кусков

Да, и нагрузка уйдёт туда же. У сервера ресурсы не резиновые.


Сервер на то и есть, чтобы нагрузку держать, тем более, такая работа планируется на ночь, когда он (сервер) пальцем в носу ковыряет.
...
Рейтинг: 0 / 0
05.02.2020, 18:55
    #39923072
zeon11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Василий 2
А через udf не вариант? Либо отдельной службой


Симонов Денис
Василий 2А через udf не вариант?


нет конечно. UDF умеет возвращать только скалярный результат, т.е. набор данных из неё не вернуть.
Выполнять запросы в контексте текущего коннекта и транзакции там тоже нельзя.

В UDR (внешние ХП) можно и то и другое, но это в 3.0

UDF тут тоже работает, через UDF'ку разбираю элементарные блоки по значениям и разгоняю их по таблицам.
В UDF'ку для ускорения загоняю сразу список значений, что мне надо получить, соответственно из UDF'ки единоразово получаю список результатов.
Так что какой-то эрзац-набор данных в процедуре, всё-таки получаю.
...
Рейтинг: 0 / 0
05.02.2020, 19:02
    #39923078
kdv
kdv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
zeon11,

по идее, из-за офигенного количества временных блобов будет пухнуть база (потом пустое место будет переиспользоваться).
http://www.ibase.ru/dbgrowth/

а значит, чем быстрее диск, тем будет быстрее обработка. Обычно на виртуалках проблемы в основном с производительностю диска, кстати. На скорости проца и памяти падает, якобы, не более 5%. А вот на диске может быть много хуже.
Я бы проверил диск crystaldiskmark.
...
Рейтинг: 0 / 0
05.02.2020, 19:14
    #39923079
zeon11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
kdv
zeon11,

по идее, из-за офигенного количества временных блобов будет пухнуть база (потом пустое место будет переиспользоваться).
http://www.ibase.ru/dbgrowth/

а значит, чем быстрее диск, тем будет быстрее обработка. Обычно на виртуалках проблемы в основном с производительностю диска, кстати. На скорости проца и памяти падает, якобы, не более 5%. А вот на диске может быть много хуже.
Я бы проверил диск crystaldiskmark.


Да, статью эту читал, да и постоянно Ваш сайт пересматриваю. Спасибо за ресурс.
...
Рейтинг: 0 / 0
05.02.2020, 19:35
    #39923089
Василий 2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Симонов Денис
нет конечно. UDF умеет возвращать только скалярный результат, т.е. набор данных из неё не вернуть.
Выполнять запросы в контексте текущего коннекта и транзакции там тоже нельзя.

В UDR (внешние ХП) можно и то и другое, но это в 3.0

Так и не обязательно, можно и имеющимися средствами извратиться. Например, в цикле вызывать UDF с блобом и позицией, с которой начинать поиск. Пока не вернет пустую строку - повторять в цикле.
...
Рейтинг: 0 / 0
05.02.2020, 21:09
    #39923113
zeon11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Василий 2
Симонов Денис
нет конечно. UDF умеет возвращать только скалярный результат, т.е. набор данных из неё не вернуть.
Выполнять запросы в контексте текущего коннекта и транзакции там тоже нельзя.

В UDR (внешние ХП) можно и то и другое, но это в 3.0

Так и не обязательно, можно и имеющимися средствами извратиться. Например, в цикле вызывать UDF с блобом и позицией, с которой начинать поиск. Пока не вернет пустую строку - повторять в цикле.


Тогда в UDF надо держать открытым объект, в данном случае TXMLDocument, и гонять его хендл из UDF в процедуру и обратно, и это будет работать скорее всего только на Classic. А может так вообще делать нельзя.
...
Рейтинг: 0 / 0
06.02.2020, 10:34
    #39923230
Василий 2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
zeon11
Тогда в UDF надо держать открытым объект, в данном случае TXMLDocument, и гонять его хендл из UDF в процедуру и обратно, и это будет работать скорее всего только на Classic. А может так вообще делать нельзя.

Да не, я имел в виду, чтобы udf делала только то, что сейчас делает процедура - извлекала куски из блоба в виде строки varchar.

Кстати, насчет размножения временных блобов неплохо бы в доки. А то только в тут https://www.ibase.ru/dbgrowth/ нашел, и то когда давал запрос целенаправленно.
...
Рейтинг: 0 / 0
06.02.2020, 11:03
    #39923257
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Василий 2,

даже если написать свою версию UDF SUBSTRING которая возвращает VARCHAR(8191), то этот блоб придётся многократно открыть, прочитать и закрыть. Причём если блоб не поточный, то для поиска нужной позиции придётся каждый раз читать его с самого начала.
Но это хотя бы уберёт временные блобы.

О производительности разных решений. Недавно баловался с написанием внешних процедур на С++ (в качестве самообучения).
Написал собственную процедуру split_int для разделения больших BLOB. Суть теста генерируем числа от 1 до 1000000 и соединяем их агрегатной функцией LIST

скрипт
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
WITH RECURSIVE r
AS (SELECT
        0 AS n,
        1 AS g
    FROM rdb$database
    UNION ALL
    SELECT
        n + 1,
        r.g
    FROM r
    WHERE n < 999),
lst
AS (SELECT
       LIST(r1.n + r2.n * 1000, ';') AS b
    FROM r r1
    JOIN r r2 ON r1.g = r2.g)
SELECT
  count(*)
FROM lst



Код: plaintext
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.
План
PLAN HASH (LST R RDB$DATABASE NATURAL, , LST R RDB$DATABASE NATURAL, )

Select Expression
    -> Aggregate
        -> Aggregate
            -> Filter
                -> Hash Join (inner)
                    -> Recursion
                        -> Table "RDB$DATABASE" as "LST R RDB$DATABASE" Full Scan
                        -> Filter
                    -> Record Buffer (record length: 41)
                        -> Recursion
                            -> Table "RDB$DATABASE" as "LST R RDB$DATABASE" Full Scan
                            -> Filter

------ Информация о производительности ------
Время подготовки запроса = 16ms
Время выполнения запроса = 625ms
Среднее время на получение одной записи = 625,00 ms
Current memory = 279 893 808
Max memory = 280 302 048
Memory buffers = 16 384
Reads from disk to cache = 0
Writes from cache to disk = 667
Чтений из кэша = 2 012


В результате получается блоб размером ~6 Мбайт. Теперь собственно разделение

тест split_int
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
WITH RECURSIVE r
AS (SELECT
        0 AS n,
        1 AS g
    FROM rdb$database
    UNION ALL
    SELECT
        n + 1,
        r.g
    FROM r
    WHERE n < 999),
lst
AS (SELECT
       LIST(r1.n + r2.n * 1000, ';') AS b
    FROM r r1
    JOIN r r2 ON r1.g = r2.g)
SELECT
    min(s.out_int) as min_int,
    max(s.out_int) as max_int
FROM lst
LEFT JOIN split_int(lst.b, ';') s ON TRUE



Код: plaintext
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.
План
PLAN JOIN (HASH (LST R RDB$DATABASE NATURAL, , LST R RDB$DATABASE NATURAL, ), S NATURAL)

Select Expression
    -> Aggregate
        -> Nested Loop Join (outer)
            -> Aggregate
                -> Filter
                    -> Hash Join (inner)
                        -> Recursion
                            -> Table "RDB$DATABASE" as "LST R RDB$DATABASE" Full Scan
                            -> Filter
                        -> Record Buffer (record length: 41)
                            -> Recursion
                                -> Table "RDB$DATABASE" as "LST R RDB$DATABASE" Full Scan
                                -> Filter
            -> Filter
                -> Procedure "SPLIT_INT" as "S" Scan

------ Информация о производительности ------
Время подготовки запроса = 32ms
Время выполнения запроса = 1s 922ms
Среднее время на получение одной записи = 1 922,00 ms
Current memory = 279 914 400
Max memory = 280 302 048
Memory buffers = 16 384
Reads from disk to cache = 0
Writes from cache to disk = 667
Чтений из кэша = 4 010


1.992 - 0.625 = 1.367 c
Т.е. процедура разбила по разделителю 6 мегабайтный блоб за 1.4 секунды.
Сильно сомневаюсь что вы сможете получить подобный результат с помощью UDF или PSQL
...
Рейтинг: 0 / 0
06.02.2020, 11:40
    #39923287
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Симонов Денис,

Если не сложно, можешь запустить на этой же конфигурации разделение процедурой PSQL?
Чтобы окончательно развеять все сомнения.

Напомню процедуру
Код: sql
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.
CREATE OR ALTER PROCEDURE LIST_TO_ROWS(
    LST BLOB SUB_TYPE TEXT)
RETURNS (
    ID INTEGER)
AS
  declare pos_ int;
  declare offset int = 1;
  declare beg int;
  declare buf varchar(30100);
begin
  if (lst is null) then exit; -- добавлено по подсказке vvm

  while (0=0) do begin
    buf = substring(lst from offset for 30100);
    pos_ = 1; beg = 1;
    while (pos_ <= char_length(buf) and pos_ <= 30000) do begin
      if (substring(buf from pos_ for 1) = ',') then begin
        if (pos_ > beg) then
          id = substring(buf from beg for pos_ - beg);
        else
          id = null;
        suspend;
        beg = pos_ + 1;
      end
      pos_ = pos_ + 1;
    end
    if (offset + pos_ - 2 = char_length(lst)) then leave;
    offset = offset + beg - 1;
    if (offset > char_length(lst)) then leave;
  end

  if (pos_ > beg) then
    id = substring(buf from beg for pos_ - beg);
  else
    id = null;
  suspend;
end

...
Рейтинг: 0 / 0
06.02.2020, 11:41
    #39923290
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
WildSery,

вечером попробую. Я этот тест на домашней машине делал
...
Рейтинг: 0 / 0
06.02.2020, 11:46
    #39923293
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Симонов Денис,

Если всё с собой - можно на любой повторить :)
Главное ведь, чтобы на одной и той же.
...
Рейтинг: 0 / 0
06.02.2020, 12:14
    #39923309
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
WildSery,

нет у меня на работе UDR той. Я же её писал для развлечения (самообучения), а не для продакшена.

Вот на другой машине

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
WITH RECURSIVE r
AS (SELECT
        0 AS n,
        1 AS g
    FROM rdb$database
    UNION ALL
    SELECT
        n + 1,
        r.g
    FROM r
    WHERE n < 999),
lst
AS (SELECT
       LIST(r1.n + r2.n * 1000, ',') AS b
    FROM r r1
    JOIN r r2 ON r1.g = r2.g)
SELECT
    min(s.id) as min_int,
    max(s.id) as max_int
FROM lst
LEFT JOIN list_to_rows(lst.b) s ON TRUE




Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
План
PLAN JOIN (HASH (LST R RDB$DATABASE NATURAL, , LST R RDB$DATABASE NATURAL, ), S NATURAL)

------ Информация о производительности ------
Время подготовки запроса = 0ms
Время выполнения запроса = 23s 510ms
Среднее время на получение одной записи = 23 510,00 ms
Current memory = 149 005 632
Max memory = 149 321 792
Memory buffers = 16 384
Reads from disk to cache = 0
Writes from cache to disk = 2 254
Чтений из кэша = 162 916

у меня дома конечно комп чуть по мощней, но не настолько же
...
Рейтинг: 0 / 0
06.02.2020, 13:13
    #39923358
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
substring BLOBа медленно
Симонов Денис,

То есть в 10 раз минимум. Спасибо.
...
Рейтинг: 0 / 0
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / substring BLOBа медленно / 25 сообщений из 45, страница 1 из 2
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]