|
|
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
В таблице table имеется уникальное поле sid . В отличие от ключевых идентификаторов, это "плотные" идентификаторы, реализующие определённую логику предметной области. При удалении записей образуются "дырки", при добавлении - сначала закрываются имеющиеся "дырки", если таких нет - (max + 1). Т.е. в процессе обработки записей поле sid приблизительно равно числу записей (тем самым, исключается неконтролируемый рост этих sid ). Задача такая: Без вспомогательных таблиц и без коррелированных подзапросов одним или несколькими запросами получить самую первую "дырку" (с минимальным значением). Факт отсутствия "дырок" определяется элементарно. Если дырок нет => (max + 1), если есть, выполняется этот самый волшебный запрос . P.S. Лет 8 эдак назад, вроде, такую задачу решал. Сейчас буду вспоминать... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.08.2015, 19:46:48 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
Cyrax_02, Левокоррелированное само объединение таблицы со двигом на единицу по сиду с последующим ордербаем и лимитом. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.08.2015, 20:02:31 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
авторЛевокоррелированное само объединение таблицы со двигом на единицу по сиду с последующим ордербаем и лимитом. Если вы имеете ввиду такой вариант: Код: sql 1. 2. 3. 4. то он даст неверный результат, если в таблице table отсутствуют первые 1 или более идентификаторов. Впрочем для решения этой "проблемы" достаточно предварительно выполнить проверку наличия (sid = 1) и если есть, выполнять этот запрос (если нет, то первой дыркой и будет sid = 1 ). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.08.2015, 20:56:52 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
Cyrax_02это "плотные" идентификаторы, реализующие определённую логику предметной областиЕсли логика не допускает движения "обратно" (т.е. если идентификаторы начинаются с sid = 1, то существует возможность построить идентификатор sid = 0) - одним запросом задача решается только с внутренним union (в качестве крайнего рассмотри случай, когда таблица пуста). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.08.2015, 21:50:29 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
Cyrax_02то он даст неверный результат, если в таблице table отсутствуют первые 1 или более идентификаторов.заюнионоллить прев копию таблицы на 0... Но тебе же надо без подзапросов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.08.2015, 22:09:30 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
авторЕсли логика не допускает движения "обратно" (т.е. если идентификаторы начинаются с sid = 1, то существует возможность построить идентификатор sid = 0) Если двигаться "обратно", то для каждого подряд идущего набора "дырок" будет получена "дырка" с максимальным (в этом наборе) sid. А нужно получать минимальный в наборе sid. Поэтому, движение "обратно" не стоит рассматривать вообще. автородним запросом задача решается только с внутренним union С внешним же - outer join. авторзаюнионоллить прев копию таблицы на 0... После объединения индекс по sid использоваться уже не будет (по отношению к этому объединению). В этом случае запрос становится бесполезным из-за полного перебора. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2015, 14:59:30 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
Cyrax_02После объединения индекс по sid использоваться уже не будет.ты бы для начала работающие варианты запросов набросал, сравнил планы и статистику выполнениявыполнения на реальных данных. А уж потом делал бы выводы... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2015, 15:29:59 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
авторты бы для начала работающие варианты запросов набросал, сравнил планы и статистику выполнениявыполнения на реальных данных. А уж потом делал бы выводы... А что - MySQL умеет применять индексы к результатам объединения ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2015, 16:08:23 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
Cyrax_02, вот решение, если есть возможность выполнять логику на клиенте Код: sql 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. Если мы решали подобную задачу в своем проекте, то мы бы при удалении заносили номер в отдельную таблицу, а при вставке брали бы свободный номер из неё. Ну и прописали бы нормализатор, который вызывался бы с вероятностью 0,05%. Код нормализатора: Код: sql 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.08.2015, 19:00:17 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
Похоже, самый быстрый вариант такой: Код: php 1. 2. 3. 4. Одним запросом и без вспомогательных таблиц быстрее - никак. Проблема данного запроса в том, что всё равно приходится один раз пробегать по всем строкам из таблицы ( table ). Соответственно, получаем линейную зависимость от числа записей в таблице - а это в целом некошерно. авторЕсли мы решали подобную задачу в своем проекте, то мы бы при удалении заносили номер в отдельную таблицу, а при вставке брали бы свободный номер из неё. Ну и прописали бы нормализатор, который вызывался бы с вероятностью 0,05% Да, можно использовать вспомогательную таблицу. Что-то подобное я реализовывал в локальном приложении (только во вспомогательной таблице у меня хранились все ранее выданные sid 'ы). Но в данном случае во вспомогательной таблице пока необходимости нет, поскольку: а) все операции с sid выполняются только в бэкэнде б) штатные операции удаления в таблице ( table ) выполняются редко в) нештатные разовые операции удаления N-го количества записей могут иметь место только в отношении последних добавленных записей - а при удалении последних добавленных записей новые "дырки" не образуются (разве что могут открыться ранее закрытые "дырки") г) поиск "дырок" вышеприведённым запросом выполняется только при их наличии, а их наличие предварительно проверяется отдельным быстрым запросом P.S. Пока на 25000 записей запрос выполняется 0.2 сек - это приемлемое время. Ну а когда счёт записей пойдёт на миллионы - можно будет задействовать и вспомогательную таблицу. Либо вычислять и запоминать "дырки" (либо в файле, либо в отдельной таблице) ежедневно ночью по крону (тем же самым запросом). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.08.2015, 22:04:29 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
Cyrax_02, вот интересно, select count(1) c1 from t where sid between N1 and N2 с индексом по СИД будет всегда быстрым при любых Н1 < Н2 ? Если так, то можно продумать алгоритм быстрого поиска делением пополам (или даже золотое сечение?). Типа если имеется 100К записей сначала делаем select count(1) c1 from t where sid between 1 and 50000 если С1 равно 50000, то дырок нет, смотрим половинку верхнуей половинки select count(1) c1 from t where sid between 50000 and 75000 если С1 меньше чем 25000 то берем следуюшее деление.... на милион записей 20 подходов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.08.2015, 02:21:07 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
авторЕсли так, то можно продумать алгоритм быстрого поиска делением пополам (или даже золотое сечение?). Позже этот вариант протестирую. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.08.2015, 12:54:53 |
|
||
|
Поиск "дырки" одним запросом
|
|||
|---|---|---|---|
|
#18+
Cyrax_02 P.S. Пока на 25000 записей запрос выполняется 0.2 сек - это приемлемое время. Ну а когда счёт записей пойдёт на миллионы - можно будет задействовать и вспомогательную таблицу. Либо вычислять и запоминать "дырки" (либо в файле, либо в отдельной таблице) ежедневно ночью по крону (тем же самым запросом). Есть ещё такое решение вашей задачи, которое мы использовали в нескольких проектах: Храним в базе искусственно созданную матрицу, заполненную навырост Код: sql 1. 2. 3. Чтобы получить очередной номер для создания (вставки записи) делаем вот так Код: sql 1. УСКОРЕНИЕ 1 Если мы знаем, что до 23500 записи у нас точно нет дырок, то Код: sql 1. УСКОРЕНИЕ 2 По хрону раз в день пересоздавать таблицу с дырками вот так Код: sql 1. 2. 3. Затем при создании каждой новой записи 1) доставать минимальную запись из этой таблицы 2) если она есть, удалять запись и использовать полученный номер 3) если таблица holes пуста, тогда получать max(sid) PS. В этот же самый хрон можно вшить нормализатор маскера: если мы знаем, что в среднем в день у нас создается 850 новых записей, а Код: sql 1. дает 0, то Код: sql 1. 2. В таблице maskerMother хранятся идентификаторы навырост в течение квартала (или даже года) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.08.2015, 22:01:07 |
|
||
|
|

start [/forum/topic.php?fid=47&msg=39031749&tid=1832794]: |
0ms |
get settings: |
8ms |
get forum list: |
10ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
30ms |
get topic data: |
7ms |
get forum data: |
1ms |
get page messages: |
35ms |
get tp. blocked users: |
1ms |
| others: | 197ms |
| total: | 295ms |

| 0 / 0 |
