Есть обект у него есть UID унакальный идентификатор в пределах базы.
В некий момент времени изменилось несколько полей что необходимо отразить в базе.
Создается точка изменения (хранится UID, point_id, time). Далие в таблицу значений сохраняютсяизменившиеся поля(у каждого есть PID унакальный идентификатор в пределах объекта).
Вобщем при работе программы получается такая штука строки — точки, столбци pid'ы. Желтые ячейки пустые.
Задача такая:
Есть point и несколько pid'ов(от 5 до 100) Надо выбрать из базы самые последние значения которые были записаны до и в заданной точки.
Сейчас делаю так
select *
from
(
select point, pid, [value]
from ValInt
where (point in (select point from points where uid=46 and point<=100000))
)a
where
(
point in
(
select max(point)
from
(
select point, pid
from ValInt
where (point in (select point from points where uid=46 and point<=100000))
)b
where b.pid = a.pid
)
)
and (pid in (20,145,555,9834,876235))
Но это медленно. И что самое противное время растет с увеличением размера базы.
А когда много pid'ов план запроса превращается в страшного мутанта
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
п.1. разверни "where (point in (select point from points where uid=46 and point<=100000))", тока не забуди индекс создать.
п.2. если таблицы большие, то имеет смысл вынести подзапрос
п.3. повыдергать максимумы от point для каждого pid тоже лучче в отдельном поздапросе и ровно один раз.
получится что-то типа:
-- п.1 + п.2select v.point, v.pid, v.[value]
into #tmp
from ValInt v
inner join points p on v.point = p.point and uid=46 and p.point <= 100000
-- п.1 + п.3select *
from #tmp a
inner join
(
select max(point) as point, pid
from #tmp
group by pid
) b on a.pid = b.pid and a.point = b.point
where a.pid in (20,145,555,9834,876235)
... << RSDN@Home 1.1 beta 1 >>
— сколько программистов надо чтобы заменить сгоревшую лампочку?
— сколько не бери, а лампочку не поменять — проблема аппаратная, программным путем не решается...
чуть не забыл.
если в #tmp попадает МНОГО записей — тоже имеет смысл создать для нее индекс. я бы порекомендовал создать его в любом случае
вот такой например:
create index IX_#tmp_point_pid on #tmp (pid, point)
... << RSDN@Home 1.1 beta 1 >>
— сколько программистов надо чтобы заменить сгоревшую лампочку?
— сколько не бери, а лампочку не поменять — проблема аппаратная, программным путем не решается...
select *
from
(
select *
from ValInt
where (pid in (20,145,555,9834,876235))
)a
where
(
point in
(
select max(point)
from
(
select *
from ValInt
where (point in (select point from points where uid=46 and point<=100000))
)b
where b.pid = a.pid
)
)
Но толку мало.
Уменя есть пара идей как реорганизовать базу. Попробую напишу.
ЗЫ Твой вариант даже с индексом оказался хуже чем первоночальный запрос. Вывод:Не парьте мозги оптимизатору.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>ЗЫ Твой вариант даже с индексом оказался хуже чем первоночальный запрос. Вывод:Не парьте мозги оптимизатору.
добрый ты...
PS а насчет запроса: скорее уж твой парит оптимизатора, а не мой
... << RSDN@Home 1.1 beta 1 >>
— сколько программистов надо чтобы заменить сгоревшую лампочку?
— сколько не бери, а лампочку не поменять — проблема аппаратная, программным путем не решается...
Здравствуйте, _MarlboroMan_, Вы писали:
_MM_>добрый ты...
Ну какой есть _MM_>PS а насчет запроса: скорее уж твой парит оптимизатора, а не мой
Парит может он и сильнее но простора для оптимизации ИМХО дает больше.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Есть обект у него есть UID унакальный идентификатор в пределах базы. WH>В некий момент времени изменилось несколько полей что необходимо отразить в базе. WH>Создается точка изменения (хранится UID, point_id, time). Далие в таблицу значений сохраняютсяизменившиеся поля(у каждого есть PID унакальный идентификатор в пределах объекта). WH>Вобщем при работе программы получается такая штука строки — точки, столбци pid'ы. Желтые ячейки пустые. WH> WH>Задача такая: WH>Есть point и несколько pid'ов(от 5 до 100) Надо выбрать из базы самые последние значения которые были записаны до и в заданной точки. WH>Сейчас делаю так WH>
WH>select *
WH>from
WH>(
WH> select point, pid, [value]
WH> from ValInt
WH> where (point in (select point from points where uid=46 and point<=100000))
WH>)a
WH>where
WH>(
WH> point in
WH> (
WH> select max(point)
WH> from
WH> (
WH> select point, pid
WH> from ValInt
WH> where (point in (select point from points where uid=46 and point<=100000))
WH> )b
WH> where b.pid = a.pid
WH> )
WH>)
WH>and (pid in (20,145,555,9834,876235))
WH>
WH>Но это медленно. И что самое противное время растет с увеличением размера базы. WH>А когда много pid'ов план запроса превращается в страшного мутанта
А так попробовать:
select point, pid, [value]
from ValInt
where ( pid, point )
in
( select ValInt.pid, max( ValInt.point)
from ValInt join points on ValInt.point = points.point and points.uid = 46
where ValInt.point < 100000
and ValInt.pid in (20,145,555,9834,876235)
group by ValInt.pid
)
select point, pid, [value]
from ValInt
where ( pid, point )in
(
select ValInt.pid, max( ValInt.point)
from ValInt join points on ValInt.point = points.point and points.uid = 46
where ValInt.point < 100000
and ValInt.pid in (20,145,555,9834,876235)
group by ValInt.pid
)
Line 3: Incorrect syntax near ','.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
WH>select *
WH>from
WH>(
WH> select point, pid, [value]
WH> from ValInt
WH> where (point in (select point from points where uid=46 and point<=100000))
WH>)a
WH>where
WH>(
WH> point in
WH> (
WH> select max(point)
WH> from
WH> (
WH> select point, pid
WH> from ValInt
WH> where (point in (select point from points where uid=46 and point<=100000))
WH> )b
WH> where b.pid = a.pid
WH> )
WH>)
WH>and (pid in (20,145,555,9834,876235))
WH>
WH>Но это медленно. И что самое противное время растет с увеличением размера базы. WH>А когда много pid'ов план запроса превращается в страшного мутанта
Не совсем понял, что нужно получить, но судя по запросу догадываюсь что нужен group by.
Примерно так:
select ValInt.*
from
ValInt inner join
(
select max(point) as point, pid
from ValInt inner join points on ValInt.point=points.point
where points.uid=46 and points.point<=100000 and ValInt.pid in (20,145,555,9834,876235)
group by pid
) a on ValInt.point=a.point and ValInt.pid=a.pid
В 57-58 раз медленней чем мой модифицированый Не смотря на то что у твоего план запроса выглядит лучше
select *
from
(
select *
from ValInt
where (pid in (20,145,555,9834,876235))
)a
where
(
point in
(
select max(point)
from
(
select *
from ValInt
where (point in (select point from points where uid=46 and point<=100000))
)b
where b.pid = a.pid
)
)
ЗЫ Добрый я всетки
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн