Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  10:53[Войти] | [Зарегистрироваться]
Ответ на вопрос № 83879

06-03-2024 04:39
Господа, возникла проблема с Firebird.

Есть вот такой запрос
DELETE FROM T1 WHERE T1.ID1 IN (SELECT T2.ID FROM T2 WHERE T2.ID1 = :param1)
Индексы по T1.ID1 и T2.ID1 имеются, T2.ID – первичный ключ.
Кажется (мне, по крайней мере) естественным, что нужно выбрать все записи из TD, используя индекс по T2.ID1, а удалять записи из T1, используя индекс по T1.ID1. Но Firebird поступил странно: по T2 он использует первичный ключ, а с T1 вообще работает по натуралу, что приводит к жутким тормозам. Как задать свой план для такого запроса, я не врубился, планы – это моё слабое место :) Можете подсказать, как здесь лучше поступить.

Если что, вопрос не критичный. Это запрос из хранимой процедуры, поэтому я тупо заменил один запрос циклом по T2, в котором для каждой записи выполняется DELETE из T1. Но просто интересно, как можно правильно сделать одним запросом.

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

11-03-2024 02:30 | Комментарий к предыдущим ответам
В запрос "вариант удаления с db_key", закралась очепятка:

    do
      delete from TD_TEST1
        where rdb$db_key = :wKey;

 

11-03-2024 02:00
>>>что запрос SELECT к одной таблице никак не сможет получить RDB$DB_KEY записи другой таблицы
  Посмотрите мой первый пост, запрос 2. По-моему, у вас именно такое соединение таблиц. Если так, то вот пример:
  Вариант удаления с ПК:

SET TERM ^ ;
create or alter procedure TD_TEST_DELETE
as
declare variable WID type of DB$DM_IDENT;
begin
  for select t1.TEST1_ID
    from TD_TEST1 t1
    join TD_TEST2 t2 on t1.TEST2_ID = t2.TEST2_ID
    into :wId
    do
      delete from TD_TEST1
        where TEST1_ID = :wId;
end^
SET TERM ; ^


  Вариант удаления с db_key:

SET TERM ^ ;
create or alter procedure TD_TEST_DELETE2
as
declare variable wKey char(8) character set OCTETS;
begin
  for select t1.rdb$db_key
    from TD_TEST1 t1
    join TD_TEST2 t2 on t1.TEST2_ID = t2.TEST2_ID
    into :wKey
    do
      delete from TD_TEST1
        where TEST1_ID = :wKey;
end^
SET TERM ; ^


11-03-2024 01:48
>>>вопрос: имеет ли смысл в моём случае (две разных таблицы) использовать rdb$db_key, будет ли это иметь преимущество перед работой через primary key?
  Слово "смысл" обычно связано с вопросом "зачем?".
  В моём представлении, программу сначала разрабатывают, чтобы она "работала", как первоначально задумывалось. А затем дорабатывают, чтобы она "хорошо работала", в соответствии с новыми котелками, появившимися после начала разработки.
  То, что "делается сначала", разрабатывается исключительно штатными средствами, по причине предсказуемости, как вашего опыта работы с таковыми, так и затраченного времени. А то что потом "дорабатывается", уже может использовать всё до чего можно дотянуться. Причём делается оно, либо, если вдруг у вас останется свободное время, либо уже в новом, дополнительном проекте.
  Поскольку rdb$db_key является: а) недокументированной возможностью FB и б) специфическим, техническим средством оптимизации запросов, а не универсальным инструментом, то использовать его при начальной разработке программы не рекомендуется.

  Поэтому, по поводу заданного вопроса, мне трудно что-либо предположить.
  По моим прикидкам, на "стандартном офисном компьютере" 15-летней давности с FB3 x84: для T1 с 1 000 000 записями, T2 со 100 000 записями и обновлением (или удалением) половины записей T1 (входящими в T2), вариант с ПК, должен отрабатывать порядка десятка секунд. Можно сказать, более чем приемлемо.
  Попробуйте проверить и провести замеры сами. У вас же теперь есть отдельный запрос выборки (в составе неявного курсора). Посмотрите на сколько различается время его работы в том и другом случае.

10-03-2024 00:05 | Сообщение от автора вопроса
Виноват-с... фигню спорол-с...

Что-то притупил и не сообразил, что запрос SELECT к одной таблице никак не сможет получить RDB$DB_KEY записи другой таблицы :-) Вопрос неактуален.

09-03-2024 02:56 | Сообщение от автора вопроса
Сорри. Не выставил правильный тип сообщения :-)

09-03-2024 02:54
В общем, я понял две вещи:

1. Одним простым запросом эффективно удалить записи не получится.

2. Я интуитивно принял правильное решение (на самом деле, оно очевидно): использовал for select do delete. Благо, у меня этот запрос в хранимой процедуре, так что execute block писать не пришлось.

Если можно, ещё один дополнительный вопрос: имеет ли смысл в моём случае (две разных таблицы) использовать rdb$db_key, будет ли это иметь преимущество перед работой через primary key? Скорее всего, нет. Но разу уж пошла такая пьянка... то лучше уточнить.

09-03-2024 00:06
>>>Есть вот такой запрос ... . Но просто интересно, как можно правильно сделать одним запросом.
  В БД Firebird, для операций update и delete данными из других таблиц используют неявные курсоры for select ... do update ... и for select ... do delete ... .
  Такой синтаксис выглядит значительно нагляднее и выразительнее, чем перечисление несколько таблиц в разделе where опереторов update или delete (как это делает oracle или ms).
  В запросе, такой неявный курсор, помещается в "исполняемый блок" execute block.
  Пример можно посмотреть там:
"UPDATE данными из других таблиц"
http://www.ibase.ru/updsame/

>>>планы – это моё слабое место...
По теме топика, рекомендую посмотреть фильм:
"Firebird 3.0: оптимизатор и планы запросов"
https://www.youtube.com/watch?v=0KITHwMNDtw

08-03-2024 23:22
>>>Как задать свой план для такого запроса, я не врубился, планы – это моё слабое место
  Не надо трогать "план запроса".
  Полагайте, что "план запроса" создан для того, чтобы пояснить вам насколько доходчиво вы объяснили серверу, что вы от него хотите. "План запроса", это такая подсказка сервера БД вам, что именно вы делаете неверно.
 
>>>Но Firebird поступил странно ... что приводит к жутким тормозам
  Тормоза вполне предсказуемы. Поясню на примере.
  Есть две таблицы: td_Test1 и td_Test2. В каждой есть первичный ключ: td_Test1.Test1_id и td_Test2.Test2_id. Таблица td_Test1 связана с таблицей td_Test2 как главная-подчинённая по ПК (читай по внешнему ключу): td_Test1.Test2_id -> td_Test2.Test2_id.

—1. простая выборка:

select *
  from td_Test1

План:

PLAN (TD_TEST1 NATURAL)

Пояснение:
  - всё выбирается как есть;
  - очевидно, что индекс на ПК не используется (незачем).

—2. простая выборка с соединением:

select t1.*
  from td_Test1 t1
  join td_Test2 t2 on t1.Test2_id = t2.Test2_id

План:

PLAN JOIN (T2 NATURAL, T1 INDEX (TD_TEST1_TEST2_IDX1))

Расширенный план:

Select Expression
    -> Nested Loop Join (inner)
        -> Table "TD_TEST2" as "T2" Full Scan
        -> Filter
            -> Table "TD_TEST1" as "T1" Access By ID
                -> Bitmap
                    -> Index "TD_TEST1_TEST2_IDX1" Range Scan (full match)

Пояснение:
  - соединение происходит по индексу в таблице T1;
  - всё что осталось, выбирается как есть.
                   
—3. простая выборка с соединением по in:

select t1.*
  from td_Test1 t1
  where t1.Test2_id in (
    select t2.Test2_id
      from td_Test2 t2
      )

План:

PLAN (T2 NATURAL)
PLAN (T1 NATURAL)

Пояснение:
  -получаем неотсортированный список из T1
  -для каждого эл-та из T2 ищем соответствие в полученном списке

Предсказуемо получаем тормоза в БД.
Потому что:
1. "В списочном же контексте (чаще всего - в IN (...)), подзапрос всегда вызывается на каждую итерацию внешнего запроса." ( http://www.ibase.ru/dpopov/ )
2. Борри Х. "Firebird руководство разработчика баз данных", Глава 21: "С точки зрения производительности предикат IN не будет полезен, когда подзапрос возвращает достаточно большое количество значений".

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Жил-был у бабушки серенький КТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования