:: Игры Разума
Re: Еще игра
Prudivus
Автор

Сообщений: 4283
Откуда: Кишинев
Дата регистрации: 14.12.2006
2Леонид
Тормозит вот этот базовый запрос (расчет следующей даты переезда):
(Select t3.kluch, t3.DataPereez, t3.nKab, Min(t4.DataPereez) As DataNext From ;
tbPereezd t3 Join tbPereezd t4 On ;
t3.kluch=t4.kluch And t3.DataPereez<t4.DataPereez ;
GROUP By t3.kluch, t3.DataPereez, t3.nKab) t5
У меня на 1000 записей он занимает 8 сек.

Если переписать его вот так:
Select t3.kluch, t3.DataPereez, t3.nKab,;
(select Min(t4.DataPereez);
FROM tbPereezd t4;
WHERE t3.kluch=t4.kluch And t3.DataPereez<t4.DataPereez) DataNext;
From tbPereezd t3;
GROUP By t3.kluch, t3.DataPereez, t3.nKab
То выигрыш получается порядка полсекунды, разница небольшая.

А вот на это:
Select t3.kluch, t3.DataPereez, t3.nKab,;
(SELECT TOP 1 t4.DataPereez;
FROM tbPereezd t4;
WHERE t3.kluch=t4.kluch And t3.DataPereez<t4.DataPereez;
ORDER BY t4.DataPereez) DataNext;
From tbPereezd t3;
GROUP By t3.kluch, t3.DataPereez, t3.nKab;
INTO CURSOR tmp
уже фокс ругается "запросы такого типа не поддерживаются".



Исправлено 1 раз(а). Последнее : Prudivus, 19.03.07 11:18
Ratings: 0 negative/0 positive
Re: Еще игра
Prudivus
Автор

Сообщений: 4283
Откуда: Кишинев
Дата регистрации: 14.12.2006
А вообще эту третью задачу можно формализовать:

Дано: таблица, которая может быть упорядочена по некоторому выражению.

create table sorttable (id int, sortexpr int)

Задание: построить выборку по таблице вида
(id, sortexpr, next_id)
где next_id - идентификатор следующей (за данной) записи согласно выражения сортировки.
Ratings: 0 negative/0 positive
Re: Еще игра
Prudivus
Автор

Сообщений: 4283
Откуда: Кишинев
Дата регистрации: 14.12.2006
MS SQL 2000 (MSDE):
declare @sorttable table (id int , sortexpr dec(9,4))
declare @i int
set @i=1
while @i <= 1000
begin
insert @sorttable values (@i, RAND()*10)
set @i = @i + 1
end
select t.*,
(select top 1 t1.id
from @sorttable t1
where t1.sortexpr > t.sortexpr
order by t1.sortexpr) next_id
from @sorttable t
order by sortexpr
Результаты (без времени на вставку записей):
-- 1000 -> 1 sec
-- 2000 -> 4 sec (при использовании временных таблиц - 2 сек.)
-- 3000 -> 9 sec (при использовании временных таблиц - 6 сек.)
-- 4000 -> 16 sec(при использовании временных таблиц - 11 сек.)
-- 5000 -> 24 sec(при использовании временных таблиц - 16 сек.)
-- 6000 -> 34 sec(при использовании временных таблиц - 23 сек.)
-- 10000-> 90 sec(при использовании временных таблиц - 60 сек.)
Видна квадратичная зависимость от количества записей, быстродействие при использовании временных таблиц примерно в 1.5 раза выше.



Исправлено 1 раз(а). Последнее : Prudivus, 19.03.07 13:29
Ratings: 0 negative/0 positive
Re: Еще игра
leonid

Сообщений: 3202
Откуда: Рига
Дата регистрации: 03.02.2006
Prudivus
А вообще эту третью задачу можно формализовать:
Дано: таблица, которая может быть упорядочена по некоторому выражению.

create table sorttable (id int, sortexpr int)

Задание: построить выборку по таблице вида
(id, sortexpr, next_id)
где next_id - идентификатор следующей (за данной) записи согласно выражения сортировки.

На фоксе, если писать несколькими операторами, это решается так
rand(-1)
create cursor st1 (sortexpr int)
for i=1 to 110000
insert into st1 values (int(rand()*1000000))
next
select recno() as id, sortexpr from st1 into cursor st2
select max(id) as id, sortexpr from st2 group by sortexpr into cursor st3
select top 100000 * from st3 order by 1 into cursor st4 nofilter
m.sc=seconds()
select id, sortexpr from st4 order by 2 into cursor st5 nofilter
select recno() as rn, id, sortexpr from st5 into cursor st6
select s1.id, s1.sortexpr, s2.id as next_id from st6 s1 left join st6 s2 on ;
s1.rn=s2.rn-1 into cursor st8
?seconds()-m.sc
Если запихнуть все это в один оператор, получается
m.sc=seconds()
select s1.id, s1.sortexpr, s2.id as next_id from ;
(select recno() as rn, id, sortexpr from ;
(select id, sortexpr from st4 order by 2) s3) s1 ;
left join (select recno() as rn, id, sortexpr from ;
(select id, sortexpr from st4 order by 2) s4) s2 ;
on s1.rn=s2.rn-1 into cursor st7
?seconds()-m.sc
Работает это чуть-чуть медленнее, по-видимому из-за того, что одинаковые селекты выполняются дважды.
Ну, а если теперь вернуться к исходной задаче, и применить вышеприведенные методы, то получается
Create Cursor tbChel (kluch c(20), Name c(10), nKab c(2) , NKab1 c(2))
Create Cursor tbPereezd (kluch c(20),DataPereez D, nKabIz c(2) , nKab c(2))
Local m.fk, m.nk, m.ok, m.sc, i
Rand(-1)
* Zapolnenie praviljnyh pereezdov dlja usera Masha
lcKluch = Sys(2015)
m.fk=Int(Rand()*90+1)
m.ok=m.fk
For i=1 To 100000
m.nk=Int(Rand()*90+1)
If m.nk=m.ok
m.nk=m.nk+1
Endif
Insert Into tbPereezd Values (lcKluch , Date()+i, Padl(m.ok,2,"0"), Padl(m.nk,2,"0"))
m.ok=m.nk
If i%100=0
Wait Window Alltrim(Str(i)) Nowait
Endif
Next
Insert Into tbChel Values (lcKluch , [Masha], Padl(m.ok,2,"0"), Padl(m.nk,2,"0"))
* Zapolnenie praviljnyh pereezdov dlja usera Pasha
lcKluch = Sys(2015)
m.fk=Int(Rand()*90+1)
m.ok=m.fk
For i=1 To 100000
m.nk=Int(Rand()*90+1)
If m.nk=m.ok
m.nk=m.nk+1
Endif
Insert Into tbPereezd Values (lcKluch , Date()+i, Padl(m.ok,2,"0"), Padl(m.nk,2,"0"))
m.ok=m.nk
If i%100=0
Wait Window Alltrim(Str(i)) Nowait
Endif
Next
Insert Into tbChel Values (lcKluch , [Pasha], Padl(m.ok,2,"0"), Padl(m.nk,2,"0"))
* Isporchennyj pereezd dlja usera Masha
Select tbPereezd
Go 90000
Replace nKabIz With Padl(Val(nKabIz)+1,2,"0")
Wait Clear
Clear
Set Talk Window
Set Talk On
m.sc=Seconds()
Select kluch, Name From tbChel Where kluch In ;
(Select Distinct t5.kluch From ;
(Select s2.kluch, s2.DataPereez, s2.nKab, s4.DataPereez As DataNext From ;
(Select Recno() As rn, kluch, DataPereez, nKab From ;
(Select kluch, DataPereez, nKab From tbPereezd Order By 1, 2) s1 ) s2 ;
left Join ;
(Select Recno() As rn, kluch, DataPereez, nKab From ;
(Select kluch, DataPereez, nKab From tbPereezd Order By 1, 2) s3 ) s4 ;
on s2.kluch=s4.kluch And s2.rn=s4.rn-1) t5 ;
Join tbPereezd t7 On t5.kluch=t7.kluch And t5.DataNext=t7.DataPereez ;
Where t5.nKab<>t7.nKabIz) Into Cursor tmp
?Seconds()-m.sc
Browse
Set Talk Off
Set Talk Nowindow
Ratings: 0 negative/0 positive
Re: Еще игра
Prudivus
Автор

Сообщений: 4283
Откуда: Кишинев
Дата регистрации: 14.12.2006
СУПЕР!

Я чуть-чуть прокомментирую:
* Это блок "технической очистки", убираются все повторяющиеся
* записи и формируется исходная структура курсора по заданию.
* Непосредственно к решению не относится. No comments.
select recno() as id, sortexpr from sorttable into cursor st2
select max(id) as id, sortexpr from st2 group by sortexpr into cursor st3
select * from st3 order by 1 into cursor st4 nofilter

Собственно решение:
* сортировка промежеточного курсора по выражению сортировки...
select id, sortexpr from st4 order by 2 into cursor st5 nofilter
* ...и формирование альтернативного id как непрерывно-возрастающего счетчика (rn)
select recno() as rn, id, sortexpr from st5 into cursor st6
** использование recno() не очень корректно с точки зрения "pure SQL",
** но в фоксе это работает (пока? нет, уже всегда! если в SP2 не изменят, что врядли)
** в других реализациях SQL для получения приемлемого быстродействия
** тоже придется использовать подобные трюки
* соединение результирующего курсора с собой же со сдвигом на одну запись
select s1.id, s1.sortexpr, s2.id as next_id from st6 s1 left join st6 s2 on ;
s1.rn=s2.rn-1 into cursor st8
** быстродействие зашкаливает!

Вариант решения одним запросом:
select s1.id, s1.sortexpr, s2.id as next_id;
from (select recno() as rn, id, sortexpr;
from (select id, sortexpr from st4 order by 2) s3) s1;
left join (select recno() as rn, id, sortexpr;
from (select id, sortexpr from st4 order by 2) s4) s2;
on s1.rn=s2.rn-1 into cursor st7
Что тут сказать: такое можно сделать только на фоксе! Очень сомнительное использование recno() в подзапросе, даже с точки зрения фокс-программиста (меня)... Но оно работает, и скорость поражает!

Ура Леониду и фоксу!



Исправлено 2 раз(а). Последнее : Prudivus, 20.03.07 12:10
Ratings: 0 negative/0 positive
Re: Еще игра
leonid

Сообщений: 3202
Откуда: Рига
Дата регистрации: 03.02.2006
Prudivus
Очень сомнительное использование recno() в подзапросе
Я тоже сильно сомневался, пока не попробовал. Думаю тут важно, что в данном подзапросе нет join-ов.
Ratings: 0 negative/0 positive
Re: Еще игра
Prudivus
Автор

Сообщений: 4283
Откуда: Кишинев
Дата регистрации: 14.12.2006
А вообще подобные решения неплохо бы оформить в виде "библиотеки решений и алгоритмов" на этом сайте.
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 5 (Гостей: 5)

© 2000-2024 Fox Club 
Яндекс.Метрика