powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / substring BLOBа медленно
25 сообщений из 45, страница 1 из 2
substring BLOBа медленно
    #39922621
zeon11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В процедуру загружаю (через 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
substring BLOBа медленно
    #39922624
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zeon11,

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

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

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


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

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


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

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

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

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


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

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

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

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

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


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


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


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

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

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

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

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

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

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


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

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

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

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

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


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

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

Кстати, насчет размножения временных блобов неплохо бы в доки. А то только в тут https://www.ibase.ru/dbgrowth/ нашел, и то когда давал запрос целенаправленно.
...
Рейтинг: 0 / 0
substring BLOBа медленно
    #39923257
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий 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
substring BLOBа медленно
    #39923287
WildSery
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис,

Если не сложно, можешь запустить на этой же конфигурации разделение процедурой 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
substring BLOBа медленно
    #39923290
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WildSery,

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

Если всё с собой - можно на любой повторить :)
Главное ведь, чтобы на одной и той же.
...
Рейтинг: 0 / 0
substring BLOBа медленно
    #39923309
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
substring BLOBа медленно
    #39923358
WildSery
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис,

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


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