Страница 1 из 1

Базовод для сасового костыля

СообщениеДобавлено: 18 сен 2012, 14:27
Parasite
Господа, кто в теме - подскажите плиз?

Имеется база данных, в которой - туева хуча одинаковых по структуре таблиц. Различны сами хранимые в таблицах данные.
Как мне сделать так, чтобы одним коротеньким селектом поискать и выбрать данные со всей кучи таблиц, а не перебирать и опрашивать каждую таблицу последовательно? Что-то туплю... :oops:

Код: Выделить всё
DB:
  |-Table0
  |  |-Col0,Col1,Col2...
  |
  |-Table1
  |  |-Col0,Col1,Col2...
  |
  |-Table2
  |  |-Col0,Col1,Col2...
.......

Надо:
SELECT * FROM <тут, собссно, сабж> WHERE <условие>
вместо
SELECT * FROM DB.Table0 WHERE <условие>; SELECT * FROM DB.Table1 WHERE <условие>; SELECT * FROM DB.Table2 WHERE <условие>;

Просто число таблиц стремится к нескольким сотням, и перебирать их уже весьма затратно (хоть и работоспособно). Вроде бы как-то можно было сделать через VIEW говорят, но что-то пока получается всякая хрень.

PS: DB = PostgreSQL
PPS: нужно для костыля к САСу, так что немножко тематическое. :)

Re: Базовод для сасового костыля

СообщениеДобавлено: 18 сен 2012, 15:16
Sigurt
Что-то кроме union ничего в голову не приходит, но по сути это не сильно отличается от кучи запросов, что уже имеется...

Либо один раз сделать
Код: Выделить всё
create view public.view1 (col0,col1,col2...) as
SELECT * FROM table1
UNION
SELECT * FROM table2

А потом запросами с представлениями и работать, но фактически не сильное отличие от того что у вас есть =)

Re: Базовод для сасового костыля

СообщениеДобавлено: 18 сен 2012, 16:45
Parasite
Там еще и дело в том, что запрос со стороны клиента можно делать только один: либо никаких последовательных переборов табличек и брать всё за раз (и до сего момента так оно и было - была всего одна табличка, но со временем она распухла до >200Гб и уже пару раз крэшилась по индексам...хорошо хоть бэкапы были), либо делать промежуточный проксик еще и на пути к базоводу, который и будет перебирать кучу селектов от себя - а выплевывать в запросившего только финальный результат....Второй вариант - корявый и угробищный. :(

Может есть какой-нибудь синтаксис селекта, в котором не надо указывать целевую таблицу (или указать * )? :) Было бы весьма красиво: SELECT * FROM * WHERE <условие> limit X, и дело с концом...

Sigurt писал(а):Что-то кроме union ничего в голову не приходит, но по сути это не сильно отличается от кучи запросов, что уже имеется...

Кстати, а можно и так попробовать, да. Ничего не мешает быть сотне-другой селектов внутри базовода - и пусть их, машинка весьма мощная...Лишь бы для стороны клиента это было прозрачно и приходил общий ответ со всех таблиц в ответ на один запрос....
Попробую, отпишусь. :)

Re: Базовод для сасового костыля

СообщениеДобавлено: 19 сен 2012, 20:15
vasketsov
Варианты:
1. UNION ALL.
2. Запускать хранимую процедуру, слить в хранимой процедуре во времянку (создать в процедуре), потом селектить из неё, на выходе времянка сама умрёт - это если СУБД поддерживает селекты наружу из хранимок.

Re: Базовод для сасового костыля

СообщениеДобавлено: 22 сен 2012, 18:36
Parasite
Что-то не выходит каменный цветок.

1.
Код: Выделить всё
SELECT * FROM "Table0" where <условие> UNION SELECT * FROM "Table1" where <условие> UNION SELECT * FROM "Table2" where <условие> UNION SELECT * FROM "Table3" where <условие>;

= работает как задумано, но перечисление таблиц и условий приближает длину строки запроса к бесконечности, как и время отработки.

2. UNION ALL - то же самое что и п.1. То есть, никакой разницы не отмечено.

3.
Код: Выделить всё
SELECT * FROM "Table0","Table1","Table2","Table3"  where "id" is not null;

дает нам еррор:
Код: Выделить всё
ERROR: column reference "id" is ambiguous
SQL state: 42702

Если убрать перечисление всех таблиц, оставив только одну (любую) - то всё работает, но только с нею.

4. Со вьюшками - беда. Киент шлет разные селекты (с разной комбинацией условий и запрашиваемых полей), и на каждую комбинацию надо делать во вьюшке (коль скоро, как я понимаю - они фиксированы на стадии "AS (<запрос>)", и со стороны клиента произвольный запрос через них не отработает)?

Re: Базовод для сасового костыля

СообщениеДобавлено: 23 сен 2012, 20:00
movnet
SELECT * FROM "Table0","Table1","Table2","Table3"
where
"Table0.id" is not null
or
"Table1.id" is not null
or
"Table2.id" is not null
or
"Table3.id" is not null;

Re: Базовод для сасового костыля

СообщениеДобавлено: 23 сен 2012, 22:24
Parasite
movnet писал(а):SELECT * FROM "Table0","Table1","Table2","Table3"
where
"Table0.id" is not null
or
"Table1.id" is not null
or
"Table2.id" is not null
or
"Table3.id" is not null;

Работает, но запрос получается еще более монструозным чем с UNION. Представьте, что таблиц - около 500 штук? Из надо будет все перечислить, причем два раза (во FROM и в OR), и еще 500 раз указать одно и то же условие на каждую...Каждый запрос займет по паре страниц текста, и работать будет точно так же неторопливо и последовательно, а выхлоп как я понимаю будет только с первой попавшейся (коль скоро тут OR а не объединение). В чем, собственно, и вопрос.

Re: Базовод для сасового костыля

СообщениеДобавлено: 24 сен 2012, 00:02
Parasite
Нашел изящное решение через наследование.

На стороне базовода (tab, в данном случае - пустая таблица-болванка со структурой, повторенной во всех наших таблицах):
Код: Выделить всё
CREATE TABLE Table1 () INHERITS (tab) ;
....
CREATE TABLE TableХХХ () INHERITS (tab) ;

Добавление новой таблицы, соответственно - одна строчка в базовод разово, ну и заполнение данными.


На стороне клиента вообще ничего менять не надо даже при добавлении новых таблиц:
Код: Выделить всё
SELECT * FROM tab;


А
Код: Выделить всё
SELECT *,tableoid FROM tab;

еще и отдает указатели на все наследованные таблицы.

Всем спасибо, все свободны. 8-)