powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / cursors benchmark: почему нельзя делать select for update where current of <C> ?
13 сообщений из 13, страница 1 из 1
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711725
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hi all

Решил тут проверить произв-сть апдейтов, которые по некоторым причинам надо делать через курсор.
Дано: таблица со 100 тыс строками, заполнена в хаотичном порядке.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
recreate table ttt(id int primary key);
commit;
insert into ttt
select r
from (
select row_number()over() r
from rdb$types,rdb$types,(select 1 i from rdb$types rows 2)
rows 100000
)
order by rand();
commit;
gstat -r -t TTT
Код: 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.
TTT (220)
    Primary pointer page: 147377, Index root page: 147424
    Total formats: 1, used formats: 1
    Average record length: 9.00, total records: 100000
    Average version length: 0.00, total versions: 0, max versions: 0
    Average fragment length: 0.00, total fragments: 0, max fragments: 0
    Average unpacked length: 8.00, compression ratio: 0.89
    Pointer pages: 1, data page slots: 614
    Data pages: 614, average fill: 52%
    Primary pages: 614, full pages: 0, swept pages: 0
    Fill distribution:
         0 - 19% = 0
        20 - 39% = 1
        40 - 59% = 613
        60 - 79% = 0
        80 - 99% = 0

    Index RDB$PRIMARY4 (0)
        Root page: 10003, depth: 2, leaf buckets: 85, nodes: 100000
        Average node length: 4.99, total dup: 0, max dup: 0
        Average key length: 3.00, compression ratio: 1.26
        Average prefix length: 2.77, average data length: 1.00
        Clustering factor: 99815, ratio: 1.00
        Fill distribution:
             0 - 19% = 0
            20 - 39% = 0
            40 - 59% = 40
            60 - 79% = 2
            80 - 99% = 43

Требуется: залочить максимально возможное число из множества мощностью 100 тыс строк, в порядке возрастания ID, используя курсор (т.к. pure-SQL-апдейт не даёт пропускать записи, залоченные конкурентами).

Производительность SQL-update оператора (приведена только для сравнения с курсорными вариантами):

Код: plaintext
1.
2.
3.
4.
    805 ms, 700087 fetch(es), 100000 mark(s)

Table                             Natural     Index    Update 
**************************************************************
TTT                                          100000    100000

Курсорные варианты:
1a. Явный курсор + холостой update с использованием where current of <C>
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
set term ^;
execute block as
  declare a int;
  declare b int;
  declare c cursor for ( select id from ttt where id between :a and :b order by id ) ;
  declare id int;
begin
  a = 0;
  b = 100000;
  open c;
  while(1=1) do begin
     fetch c into id;
     if ( row_count = 0 ) then leave;
      update ttt set id=id where current of c; 
  end
  close c;
end
^
set term ;^
commit;
1b. Неявный for-курсор + холостой update с использованием where current of <C>:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
set term ^;
execute block as
  declare a int;
  declare b int;
begin
  a = 0;
  b = 100000;
  for select id from ttt where id between :a and :b order by id  as cursor c
  do begin
     update ttt set id=id where current of c;
  end
end
^
set term ;^
commit;
2a. Неявный for-курсор + холостой update с доступом по rdb$db_key:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
set term ^;
execute block as
  declare a int;
  declare b int;
  declare dbkey char(8) character set octets;
  declare id int;
begin
  a = 0;
  b = 100000;
  for
      select rdb$db_key from ttt where id between :a and :b  order by id 
      into dbkey
  do begin
     update ttt set id=id where rdb$db_key = :dbkey;
  end
end
^
set term ;^
commit;
2b. Неявный for-курсор + select for update с доступом по rdb$db_key:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
set term ^;
execute block as
  declare a int;
  declare b int;
  declare dbkey char(8) character set octets;
  declare id int;
begin
  a = 0;
  b = 1000000;
  for
      select rdb$db_key from ttt where id between :a and :b  order by id 
      into dbkey
  do begin
     select id from ttt where rdb$db_key = :dbkey for update with lock into id;
  end
end
^
set term ;^
commit;

Еще были сделаны два варианта для холостого апдейта и select for update with lock, в которых вместо rdb$db_key использовался доступ по ID - они аналогичны 2a & 2b (но проигрывают им).

Итог сравнения - см. аттач.
Если коротко, то рулят варианты 1a & 1b. Из плана и статистки непонятно, впрочем, за счет чего они обгоняют варианты с доступом через rdb$db_key, ну да ладно.

Вопрос, соб-сно, простой: а почему, объявив курсор <C>, нельзя делать что-то типа этого:
Код: sql
1.
select id from ttt where current of <C> for update with lock into v_id;

- ?
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711738
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид,

потому что через rdb$db_key поиск всё же идёт, а при применении where current of мы уже находимся на нужной записи.
Читай http://www.ibase.ru/devinfo/dataaccesspaths.htm#chapter113 и http://www.ibase.ru/devinfo/dataaccesspaths.htm#chapter13
и сравни
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711747
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дык я знаю, что при применении where current of мы уже находимся - ну так и что тогда мешает залочить эту "текущую" запись не холостым апдейтом, а "как-то по-другому" ? (но тут лишь одно "другое" средство: select for update with lock...)
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711748
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид> - ну так и что тогда мешает

А что мешает?

Таблоид> но тут лишь одно "другое" средство: select for update with lock...)

И какая же между ними будет разница?
Сэкономленный оператор что ли? :)

P.S. Способов, кстати, больше одного
и даже больше двух, но нормальный
всего один (with lock).
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711755
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гаджимурадов РустамТаблоид> но тут лишь одно "другое" средство: select for update with lock...)

И какая же между ними будет разница?
Сэкономленный оператор что ли? :)Глянь в аттач, сравни 2а и 2b: в первом 200 тыс IR'ов + 100 тыс Update'ов, во втором - только 200 тыс IR'ов.
Теперь смотрим также на пару 1a vs 1b: в обоих по 100 тыс IR'ов + 100 тыс Update'ов.
Я хочу понять, какая будет скорость, если делать что-то типа:
Код: sql
1.
select id from CURRENT OF <C> for update with lock  into ...

-тут ведь будет только 100 тыс IR'ов, которые возникли при работе самого курсора, но должно быть 0 (ноль) update'ов.

Гаджимурадов РустамP.S. Способов, кстати, больше одного и даже больше двух, но нормальный всего один (with lock).Ткни, плз, в эти самые "ненормальные больше двух".
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711758
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид> Я хочу понять, какая будет скорость

А зачем ? Практический пример привести придумать
можешь или какдемический интерес, как обычно?
И кто/что мешает проверить, кстати? Что не получается?

> Ткни, плз, в эти самые "ненормальные больше двух".

Да мало ли какие извращения можно придумать,
типа селекта из процедуры с апдейтом и т.п.
Есть кошерный дедовский способ, есть его
более кошерная реализация с With Lock-ом -
все остальное не лучше и от лукавого.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711759
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
> какдемический интерес, как обычно?

Оговорка по Фрейду, аднака.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711815
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид- ну так и что тогда мешает залочить эту "текущую" запись не холостым апдейтом, а "как-то по-другому" ? (но тут лишь одно "другое" средство: select for update with lock...)

что мешает залочить их в верхнем селекте?
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711825
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов ДенисТаблоид- ну так и что тогда мешает залочить эту "текущую" запись не холостым апдейтом, а "как-то по-другому" ? (но тут лишь одно "другое" средство: select for update with lock...)что мешает залочить их в верхнем селекте?хм... надо будет проверить, что там будет, когда часть записей заняты конкурентами.
ГРПрактический пример привести придумать можешь или какдемический интерес, как обычно?N produсers -> M consumers, потребители должны обработать одни и те же записи в порядке FIFO. Лок-конфликты неизбежны. Но логика допускает, что если запись сейчас занята, то можно перейти для обработки к следующей.
Не знаю, практический это пример для тебя или нет.
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38711887
dimitr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ТаблоидИз плана и статистки непонятно, впрочем, за счет чего они обгоняют варианты с доступом через rdb$db_key
100000 IRs vs 200000 IRs

Таблоиддолжно быть 0 (ноль) update'ов
не верь глазам своим (с) WITH LOCK просто не показывается в статистике. А на самом деле там есть точно такие же апдейты, как и при холостых.
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38712046
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dimitrне верь глазам своим (с) WITH LOCK просто не показывается в статистике. А на самом деле там есть точно такие же апдейты, как и при холостых.а это можно подправить, чтобы показывались ? или уже "не в этой жизни" (С) - ?
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38712110
dimitr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид,

в 3.0 будет такая статистика, но не буду обещать что ее выведет наружу isql...
...
Рейтинг: 0 / 0
cursors benchmark: почему нельзя делать select for update where current of <C> ?
    #38712124
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dimitrв 3.0 будет такая статистика, но не буду обещать что ее выведет наружу isql...Это не страшно. Статистика isql - она ведь для доверчивых только. Трейс наше всё.
...
Рейтинг: 0 / 0
13 сообщений из 13, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / cursors benchmark: почему нельзя делать select for update where current of <C> ?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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