Модераторы: skyboy
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Иерархический подсчет элементов 
:(
    Опции темы
zheka1980
Дата 20.9.2014, 23:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 3.8.2014

Репутация: нет
Всего: нет



Господа, есть у меня иерархический каталог ссылок.

То есть одна таблица в которой записи типа:
запись 1:  id=1  caption="ул.Иванова" parent="г. Мухосранск"
запись 2:  id=2  caption="дом 1"          parent="1"
запись 3:  id=3  caption="дом 2"          parent="1"
запись 4:  id=4  caption="кв.4"            parent="3"

Структура (иерархия) строится по взаимосвязям id и parent, то есть, если я хочу узнать список домов на улице Иванова, я ищу все записи у которых id=1, если меня интересуют номера квартир в доме 2, я ищу все записи у которых id=3 и так далее.


Теперь вопрос - я хочу получить список всех квартир на улице Иванова.
МОжно решить эту задачу формально - получить массив из домов, и каждый элемент этого массива обрабатывать  запрашивая по очереди список квартир, но это накладно.

Как мне одним запросом в MySQL получить все квартиры на улице Иванова?
PM MAIL   Вверх
ТоляМБА
Дата 21.9.2014, 13:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Котэ
***


Профиль
Группа: Завсегдатай
Сообщений: 1607
Регистрация: 15.12.2004

Репутация: 10
Всего: 252



Цитата(zheka1980 @  21.9.2014,  01:04 Найти цитируемый пост)
Теперь вопрос - я хочу получить список всех квартир на улице Иванова.
Будет у вас список из 100 квартир № 1, что будете с ним делать?

Добавлено через 4 минуты и 38 секунд
Вот вместе с домами:

Код
Select T2.caption, C.caption
from Table_2 T2
inner join
(Select T1.id, T1.caption, T1.parent
from Table_2 T1
inner join
(select T.id
from Table_2 T
inner join
(select id
from table_2
where caption='ул.Иванова' and parent='г. Мухосранск') as A
on t.parent=a.id) as B
on T1.parent=B.id) as C
on T2.id=C.parent
order by 1, 2

PM   Вверх
zheka1980
Дата 21.9.2014, 14:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 3.8.2014

Репутация: нет
Всего: нет



Цитата

Будет у вас список из 100 квартир № 1, что будете с ним делать?

1. считать, сколько всего квартир.
2. выбирать случайную квартиру, пофиг из какого дома, главное чтобы была с улицы Ивнова.
PM MAIL   Вверх
ТоляМБА
Дата 21.9.2014, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Котэ
***


Профиль
Группа: Завсегдатай
Сообщений: 1607
Регистрация: 15.12.2004

Репутация: 10
Всего: 252



zheka1980, так вам мой вариант с выводом квартир и домов подходит или оставить только квартиры?
PM   Вверх
zheka1980
Дата 21.9.2014, 20:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 3.8.2014

Репутация: нет
Всего: нет



Пока не испытывал. НИчего убирать не надо, попробую сам разобраться.
Спасибо за помощь.
PM MAIL   Вверх
zheka1980
Дата 21.9.2014, 20:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 3.8.2014

Репутация: нет
Всего: нет



Уточню задачу. Видимо без вашей помощи не обойдусь.
Дело в том, что квартиры у меня в отдельной таблице "flats", в этой таблице есть автоинкрементное поле id, и parent, привязывающий к записи номера дома в таблице town (города и улицы находятся в таблице "town")


В общем задачи две, можно, и даже нужно каждую из них решить отдельным запросом.
1. На входе имеем id улицы Иванова, то есть 1, это будет входным параметром, вычисляемым в php скрипте, и передаваемым в функцию.
Нужно посчитать сколько в таблице flats имеется записей, у которых parent привязан к тому дому в таблице "town", который в свою очередь привязан к улице Иванова. Но оперировать надо не caption="ул.Иванова", а id, который, как уже сказано, равен 1
2. То же самое, но получить нужно массив из 10 первых записей таблицы "flats", которые я буду сортировать по параметрам. Ну грубо говоря, запрос должен оканчиваться на "ORDER by rank LIMIT 10"

Спасибо.

Это сообщение отредактировал(а) zheka1980 - 21.9.2014, 20:25
PM MAIL   Вверх
Akina
Дата 22.9.2014, 07:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 106
Всего: 454



Для эффективного решения такого рода задач необходимо перейти на иной способ хранения. Например, на nested set.
Либо пойти на переопределение данных - например, хранить материализованный путь узла (полный адрес).


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
zheka1980
Дата 22.9.2014, 18:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 3.8.2014

Репутация: нет
Всего: нет



Нашел статью вроде бы о том, что мне нужно - http://club.shelek.ru/viewart.php?id=307

Там написано - создать таблицу с такими-то параметрами. Я создал.
Дальше предлагается сделать это
Код

CREATE PROCEDURE fetch_subtree_ids(IN base INT UNSIGNED)
BEGIN
    DECLARE ids TEXT DEFAULT '';

    SET @parents = base;
    SET ids = base;

    loop1: LOOP
        SET @stm = CONCAT(
            'SELECT GROUP_CONCAT(id) INTO @parents FROM test1',
            ' WHERE parent_id IN (', @parents, ')'
        );

        PREPARE fetch_childs FROM @stm;
        EXECUTE fetch_childs;
        DROP PREPARE fetch_childs;

        IF @parents IS NULL THEN LEAVE loop1; END IF;

        SET ids = CONCAT(ids, ',', @parents);
    END LOOP;

    SET @stm = CONCAT('SELECT id FROM test1 WHERE id IN (', ids, ')');

    PREPARE fetch_childs FROM @stm;
    EXECUTE fetch_childs;
    DROP PREPARE fetch_childs;
END;




Я не понял - это как, целиком скормить MySQL ? Мой сервер подавился этой строкой.

Это сообщение отредактировал(а) zheka1980 - 22.9.2014, 18:45
PM MAIL   Вверх
zheka1980
Дата 22.9.2014, 22:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 3.8.2014

Репутация: нет
Всего: нет



Эх... пока ждал ответа и, почитывая статейки, тихо ужасался nested set, решил все-таки попробовать подсчитывать рекурсивной функцией на PHP.
То есть, перебираю всех потомков до самого дна (то есть до первого "бездетного" потомка), попутно составляя список этих самых бездетных потомков. 
Получилось около 400 запросов
Далее склеиваю строку типа
Код

SELECT * FROM flats WHERE parent IN('385','386','387','388',............... ВСЕГО около 400 элементов )


Забил таблицу flats мусором из 1500 записей. И выполнил в ней поиск вышеуказанной строкой.
Заняло 0.0042 сек. (Комп - Core2Dou 3 ГГц)



Ответьте на последний вопрос и я от вас отстану: 
В идеале планируется 100 000 записей, элементов каталога 400, вложенность - 3-4, не более, скажите, сканирование 400 запросами  и одним, 401-м, но длиннющим запросом выборка - это будет насилием над MySQL или если работает, то нормально?

PM MAIL   Вверх
Akina
Дата 23.9.2014, 08:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 106
Всего: 454



Цитата(zheka1980 @  22.9.2014,  23:19 Найти цитируемый пост)
решил все-таки попробовать подсчитывать рекурсивной функцией на PHP.

Организуй то же на стороне сервера на курсорах - сэкономишь на трафике и уж точно не проиграешь по скорости.
Цитата(zheka1980 @  22.9.2014,  23:19 Найти цитируемый пост)
Получилось около 400 запросов Далее склеиваю строку типа

Смотри не вылети за размер пакета. Будет не очень приятно...
Цитата(zheka1980 @  22.9.2014,  23:19 Найти цитируемый пост)
тихо ужасался nested set

Это ты просто не "въехал" в их идеологию. Ренально там всё достаточно просто. Тем более что запросы шаблонные, и их типов немного, шаблоны можно параметризовать и захардкодить - или вообще выволочь на сервере в хранимки.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
=Женек=
Дата 23.9.2014, 08:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 548
Регистрация: 20.2.2005

Репутация: нет
Всего: 1



Цитата

Это ты просто не "въехал" в их идеологию. 

Можете на пальцах объяснить практический смысл left key и right key?
Исходя из чего они формируются и самое главное, что они дают?

Цитата

Смотри не вылети за размер пакета. Будет не очень приятно...


А каков он в среднем?

Добавлено @ 08:31
Цитата

Организуй то же на стороне сервера на курсорах - сэкономишь на трафике и уж точно не проиграешь по скорости.


Секунду.. PHP и MySQL ведь на одном сервере. О каком трафике идет речь?
И что такое курсоры?

Это сообщение отредактировал(а) =Женек= - 23.9.2014, 09:05
PM MAIL   Вверх
zheka1980
Дата 23.9.2014, 20:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 3.8.2014

Репутация: нет
Всего: нет



В смысл Nested Set въехал. По сути это та же рекурсия, мой скрипт проходит по дереву каталога тот же путь, что и leftkey и rightkey. 
Только у моего скрипта это как-то само получается, а тут все разжевывать надо.
Пытаюсь понять, насколько MySQL будет быстрее с этим справляться.

Хм... а ведь в Nested Sets это будет даже проще и точно быстрее. Нужно просто выбрать записи, где разница между leftkey и rightkey не больше единицы - это и будут концевые, "бездетные" узлы. 
Но этой процедурой мы лишь избавляем MySQL от 400 запросов.
Но еще нужно выбрать в таблице №2 все элементы, принадлежащие одному из 400 идентификаторов, полученных в предыдущем запросе.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | MySQL | Следующая тема »


 




[ Время генерации скрипта: 0.0843 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.