powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / Стратегия соединения Full Outer Join
9 сообщений из 9, страница 1 из 1
Стратегия соединения Full Outer Join
    #32853644
Фотография Ggg_old
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Разбираясь в причинах тормознутости одного изх своих скриптов, обнаружил, что причиной является выбор (причем не всегда) неоптимального (с моей точки зрения) плана запроса при внешнем объединении двух таблиц. Что-бы было о чем говорить я написал тестовый запрос, на котором ситуация видна:
Итак:
две таблицы big_table, small_table, кол-во записей в которых оличается на 1-2 порядка. Таблицы содержат два поля "rлюч" и "значение".В обеих содержатся уникальные значения, часть которых в обеих таблицах может пересекаться. Надо сделать с этими таблицами внешнее соединение по ключу. В записях, где ключи совпадают, значение брать из small_table, иначе значение брать той таблицы, ключ которой имеется в записи.

Код: 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.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
//Создаем таблицы и заполняем их тестовыми значениями
//На план запроса влияют:
// - соотношение @big_size и @small_size
// - наличие ключей/индесов на таблицы
begin
	declare @big_size int;
	declare @small_size int;
	declare @i int;
	drop table big_table;
	create table big_table
	(
		b_id int not null,		
		b_value int not null,
		//constraint b_id primary key (b_id),
		pctfree  0 
	);
	drop table small_table;
	create table small_table
	(
		s_id int not null,		
		s_value int not null,
		constraint s_id primary key (s_id),
		pctfree  0 
	);
	
	//Тестовые данные
	set @big_size= 10000 ;
	set @small_size= 100 ;
	set @i= 1 ;
	while @i<=@big_size loop
		insert into big_table( b_id, b_value )
			values (@i, @i);
		set @i=@i+ 1 ;
	end loop;
	set @i= 1 ;
	while @i<=@small_size loop
		insert into small_table( s_id, s_value)
			values (@i* 2 ,  0 );
		set @i=@i+ 1 ;
	end loop;
end


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
select
		( 
			case ifnull(b.b_id, 'y')
				when 'y' then s.s_id
				else b.b_id
			end 
		) as t_id,
		( 
			case ifnull(s.s_id,'y')
				when 'y' then b.b_value
				else s.s_value
			end 
		) as t_value
	from 
		big_table b full outer join small_table s
			on (b.b_id=s.s_id)
	order by  1 ,  2 ;
конкретно в этом запросе сервер АСА 9,02 выбрал
NESTED LOOP FULL OUTER JOIN - и на обе таблицы SEQUENTAL SCAN что совсем неоптимально. Если зпдпть на обе таблицы Primary KEY, то система может выбрать MERGE JOIN. Играясь параметрами мне ни разу не удалось добиться выбора HASH JOIN. Иногда, даже при наличии индексов необходимо хинтовать, что бы избежать NESTED LOOP FULL OUTER JOIN.
...
Рейтинг: 0 / 0
Стратегия соединения Full Outer Join
    #32853722
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ASA 9.0.2.2542
кэш 32-256 мб, P4 2400 (Hyper Trading), СУБД разрешено использование обоих процессоров. БД на 2 кб страницу, хотя сервер запущен на 8 кб страницу (используются другие БД).

Выполнил скрипт создания и заполнения таблиц. Отработал менее секунды, в таблицы как и полагается занеслось 10 000 и 100 записей.

Выполнил запрос - 0,266 сек, по плану запроса стоит сортировка обоих таблиц по b_id и s_id во временные таблицы с генерацией поля связи $rowid, которые потом соединяются через алгоритм "Full Outer Merge Join (full outer join)", после которого во временную производится сортировка по вычисляемым полям запроса в времянку и возвращается результат на 10 000 записей. Вполне нормальный план и нормальное время выполнения с моей точки зрения.

Прилагаю XML версию плана запроса.
...
Рейтинг: 0 / 0
Стратегия соединения Full Outer Join
    #32853738
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Переписал чуть запрос, чтобы быстрее работали вычисления:
Код: plaintext
1.
2.
3.
4.
5.
6.
select 
  IsNull(b.b_id, s.s_id) AS t_id, 
  IF s.s_id IS NULL THEN b.b_value ELSE s.s_value ENDIF AS t_value
from 
  big_table b 
    full outer join small_table s on (b.b_id=s.s_id)
order by  1 ,  2 ;
стало выполняться за 0,219 - предыдущий план не поменялся.

Повесил на big_table первичный ключ. План запросов не поменялся. Сделал первичные ключи таблиц кластерными и перестроил их - план запросов не поменялся. В общем говоря добиться "NESTED LOOP FULL OUTER JOIN" мне так и не удалось. СУБД за время всех экспериментов так и не слезла с минимально выделенных 32 мб. Добиться HASH соединения на таком обьеме и не удастся, так как овчинка выделки не стоит - ширина big_table - 8 байт, что слишком мало весит для 10000 записей и спокойно помещается полностью в кэш. Hash алгоритмы на самом деле очень сильно напрягают процессор и если можно обойтись кэшем и Work Table, то СУБД пойдет этим путем:
Код: plaintext
1.
2.
SELECT *
FROM sa_table_page_usage ( )
WHERE TableName = 'big_table'
TableIdTablePagesPctUsedTIndexPagesPctUsedIPctOfFileTableName5611065771911'big_table'

Так что смотрите план, который я поместил и сравнивайте со своим. Может быть дело в настройках БД или сервера.
...
Рейтинг: 0 / 0
Стратегия соединения Full Outer Join
    #32853786
Фотография Ggg_old
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня Cel2.5 WinXP Home. Под сервер выделяется 20-64Мб. Все остальное одинаковое.
Теперь интересное:
Тот же скрипт, который работал через JNLFO, запускаю еще раз, и получаю
ваш план. Запускаю еще раз - снова JMFO, снова запускаю несколько раз - все нормально. И где-то на 5-1 шестой запуск - снова JNLFO.
Т.е выбор плана, на незагруженном ничем сервере, на одном и том же запросе меняется. ASCRUS, попробуйте позапускать скрипт несколько раз. Попробуйте увеличить кол-во строк в обеих таблицах в раз 10, т.е 100тыс и 1 одна тыс строк соответсвенно.
Жду результатов.
...
Рейтинг: 0 / 0
Стратегия соединения Full Outer Join
    #32854117
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Очищаю таблички:
Код: plaintext
1.
truncate table big_table;
truncate table small_table;

Заполняю их на 100000 и 1000 соответствующе:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
begin
	declare @big_size int;
	declare @small_size int;
	declare @i int;
	
	//Тестовые данные
	set @big_size= 100000 ;
	set @small_size= 1000 ;
	set @i= 1 ;
	while @i<=@big_size loop
		insert into big_table( b_id, b_value )
			values (@i, @i);
		set @i=@i+ 1 ;
	end loop;
	set @i= 1 ;
	while @i<=@small_size loop
		insert into small_table( s_id, s_value)
			values (@i* 2 ,  0 );
		set @i=@i+ 1 ;
	end loop;
end;

commit;
ISQLExecution time: 3.094 seconds
Execution time: 0.015 seconds

Проверяем кол-во записей:
Код: plaintext
1.
SELECT Count(*)
FROM big_table;
ISQLExecution time: 0.078 seconds
вернулось значение 100000.

Код: plaintext
1.
SELECT Count(*)
FROM small_table;
ISQLExecution time: 0 seconds
вернулось значение 1000.

Выполняю запрос:
ISQLExecution time: 2.109 seconds
вернулось 100000 записей. План запроса такой же - с "Full Outer Merge Join (full outer join)".

Хорошо, добавляю в big_table еще 100000 записей (причем опять же с b_id начиная с значения 1) - теперь в таблице каждая запись дублируется. Первичного ключа на нее нет.
ISQLExecution time: 2.219 seconds

Выполняю запрос:
ISQLExecution time: 5.125 seconds
План запроса теперь с "Full Outer Nested Loops Join (full outer join)" - то есть идет скан обоих таблиц, обьединение по этому алгоритму, далее сортировка во времянку и выдача клиенту. Возвращено 200000 записей.

Прилагаю этот план запроса.
...
Рейтинг: 0 / 0
Стратегия соединения Full Outer Join
    #32854138
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Далее вешаю индекс:
Код: plaintext
CREATE INDEX "b_id" ON "DBA"."big_table" ( "b_id" ASC ) IN "SYSTEM";

Выполняю запрос - опа - план с MERGE. Следующее выполнение - план с NESTED LOOPS. Соотвествующе делаю вывод - пока записей мало или в кэше, то используется MERGE, если в кэше их всех нет (то есть не помещаются), то используется NESTED LOOPS.

Как только я кол-во записей увеличил до 200000, ASA решила подобрать памяти до 48 мб.

Теперь пишем эквивалент Вашему запросу:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT s.s_id, s.s_value
FROM small_table s
  LEFT JOIN big_table b ON b.b_id = s.s_id
UNION ALL
SELECT b_id, b_value
FROM big_table
WHERE b_id NOT IN (
      SELECT s_id
      FROM small_table )
ORDER BY  1 ,  2 
ISQLExecution time: 3.344 seconds
Делает он то же самое, так же возвращает 200000 записей, естественно план запроса другой (прилагается ниже). Однако здесь я явно указал, что выбрать все записи из small_table, помноженное на кол-во таких же записей в big_table и присоединить к ним записи из big_table, которых нет в small_table. Если бы по условию задачи нам нужно было бы выбрать все записи из small_table (т.е. игнорируя дублирующиеся похожие в big_table) и только те, которые из big_table, которых нет в small_table, то тогда запрос был бы еще легче:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
SELECT s.s_id, s.s_value
FROM small_table s
UNION ALL
SELECT b_id, b_value
FROM big_table
WHERE b_id NOT IN (
      SELECT s_id
      FROM small_table )
ORDER BY  1 ,  2 [/quot]
...
Рейтинг: 0 / 0
Стратегия соединения Full Outer Join
    #32856763
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А где все "прилагаемые" планы запросов ? Я что-то не вижу.
...
Рейтинг: 0 / 0
Стратегия соединения Full Outer Join
    #32856826
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivА где все "прилагаемые" планы запросов ? Я что-то не вижу.
Они прилагаются в присоединенных XML файлах для сообщений. В ASA графические планы запросов из ISQL можно сохранять в XML файлы и открывать их в ISQL - очень удобно, наглядно, а главное со всеми опциями сервера, БД и статистикой - между прочим это описано в FAQ :)
...
Рейтинг: 0 / 0
Стратегия соединения Full Outer Join
    #32857240
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Странно. Я из дома вложения почему-то не видел.
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / Стратегия соединения Full Outer Join
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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