AVK>JanaDatabase db = new JanaDatabase(""); AVK>db AVK> .From<TestClass>() AVK> .Where(delegate(TestClass src) AVK> { return src.Name != ""; }) AVK> .OrderBy<string>(delegate(TestClass src) AVK> { return src.Name;}) AVK> .Select<NameTuple>(delegate(TestClass src) AVK> { return new NameTuple(src.Name); }); AVK>[/c#] AVK>Конкретизирую вопрос: если у нас нет индексов все замечательно — реализация упомянутых методов будет тривиальна. А вот если они есть, то возникает вопрос как и на каком основании их использовать. Навскидку вижу два варианта: AVK>1) Анализ кода лямбды на предмет обнаружения понимаемых условий. В частности в примере несложно понять как использовать индекс по Name
Речь о том, что все таки нужен вменяемый оптимизатор. В одной руке у него логический план, сформированный именно в виде лямбд. В другой руке — статистика базы (примитивная статистика есть всегда, как минимум в виде Unique и FK Constraints). На выходе именно он должен выдавать план запроса.
Я думаю, более-менее приемлемый оптимизатор не должен весить слишком много. Особенно с учетом однопользовательскости — не надо учитывать риски параллельных изменений. AVK>2) Введение двух форм методов — один с лямбдой, другой с параметрами, описывающими работу с индексом.
Вторая форма является аналогом хинтов SQL серверов. Она важна для эксплуатации, т.к. именно при ней возникает время и желание подкрутить планы для подъема производительности еще на 1.5%. Для девелопера она зло: во-первых, приходится разбираться с тем, что и как там внутри работает (фактически, переделывая работу оптимизатора), во-вторых, ограничивает маневр оптимизатора. AVK>Первый вариант удобнее для использования, но сложнее в реализации и чреват непредсказуемыми эффектами, второй значительно стабильнее, но запутывает код и усложняет добавление индексов для оптимизации. Какой вариант предпочтительнее? Или может существует третий вариант?
Да никаких других вариантов нет. Два полюса с промежуточными вариантами, типа "этот джойн надо выполнить первым, а остальные — как хочешь".
Я лично за то, чтобы отказаться от ручного указания хинтов.
Да, кстати, для настольной базы есть хороший шанс, что промежуточные результаты вполне поместятся в памяти. Это означает, что оценка стоимости сильно упрощается — настоящий оптимизатор обязан учитывать перспективы запросов, которые сначала делают full outer join миллиона с миллионом, и только потом выбирают из этого данные. Там все подряд приходится применять — сброс результатов на диск; специальные алгоритмы лукапа по этим результатам и прочая муть.
На самом деле есть еще один принципиальный вопрос: какие типы операторов допустимы?
В полной реляционной модели самые проблемные — это джойны/проекции и группировка.
Агрегатные запросы мало того, что имеют тенденцию плохо оптимизироваться, они еще и усложняют type inference. К примеру, если мы агрегируем тупл (string, int32), вычисляя Max() от второго поля по первому, то тип результирующего тупла — тоже (string, int32). А если Sum, то по-хорошему это должно быть (string, int64), иначе есть риск overflow (это я заодним предположил ограничение на 2^32 строк в любом релейшне).
Навигационный подход удобен тем, что он никогда не возвращает никаких туплов, не описанных явно в метаданных.
Мораль в том, что надо понять, чего собственно хочется — либо полная реляционная модель (вместе со всеми экзотическими фичами типа non-equality join, джойнов с вычисляемыми полями, агрегатов с окном и прочей экзотикой), либо ограниченная модель, в которой удобно и быстро выполняются некоторые основные операции.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
AndrewVK wrote: > Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД > с учетом сужения класса решаемых задач и использования новых технологий > и подходов.
Как FireBird
> 1) in process или out of process?
Оба варианта.
> 2) Физическая структура хранения на диске — алгоритмы, разбиение на > файлы etc
Один файл на базу.
> 3) Описание метаданных > 4) Способ формирования запросов
Как обычно.
> 5) Контроль на уровне БД. Вобще разграничение функций между движком БД и > прикладным кодом
Как обычно.
> 6) Алгоримты деплоймента
Скопировать файлы базы и dll-ки драйвера (для inproc).
А вообще, все должно быть как можно проще и легковеснее.
Здравствуйте, GlebZ, Вы писали:
AVK>>+1000! GZ>Только это сильно усложнит систему хранения и операций с ним. Да и статистику, если будешь делать, также.
Sinclair wrote:
> S>>А в чем собственно затык? Язык SQL уже собственно turing-complete. > GZ>В честь чего? Может ты имел ввиду T-SQL? > Нет, зачем? Для справки: исчисление функций, где есть функция 0, > инкремент, и выбор n-ого аргумента, является turing-complete.
Неверно. Оператор рекурсии забыл.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Max404.NET, Вы писали:
MN>а чем msde(2005express) не устраивает?
однако по прежнему есть ряд применений, для которых их навороты не нужны, равно как не нужен оверхед, связанный с многопользовательским доступом и сложное администрирование
Здравствуйте, Anton Batenev, Вы писали:
AVK>>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД
AB>Как MS-Access, только с триггерами
Этой каки я уже накушался, больше не надо. И нафига настольной БД триггеры?
Здравствуйте, Cyberax, Вы писали:
C>Начали мы сохранять изменения — а тут кот выдернул шнур питания (у нас C>настольная БД). Вот тут-то транзакционность с ACID очень даже пригодится.
Тут не ACID, тут A. И, в отличии от больших БД, здесь можно ограничиться только Redo Only логом.
I здесь не нужно, в силу того, что БД однопользовательская, D здесь тоже обеспечит аккуртная реализация логгирования, C — это отдельная тема для обсуждения, не думаю что весь набор больших БД здесь сильно необходим...
Здравствуйте, Cyberax, Вы писали:
>> Ну и? Что я должен был увидеть? C>Прикладной код (редактирование и т.п.) отделен от логики транзакций. C>Например, мы можем без всякого изменения кода отредактировать пачку из C>10 писем, а потом разом сохранить.
Я тебя про другое спрашивал — зачем отдельно иметь транзакции в БД, отдельно их обертки в прикладном коде.
Рекомендую почитать в SQL BOL про организацию файлов MDF. Там все довольно внятно расписано. Не думаю, что стоит изобретать какой-то более хитрый велосипед; разве что покрутить стратегии компактификации БД. В остальном изменения в Yukon сделаны в нужную сторону. К примеру, varchar(max) и varbinary(max) — это просто the must для этой потенциальной встраиваемой БД. Потому что не стоит парить разработчика выбором длины поля типа string и вопросами перехода на Memo. Должны храниться просто System.String, и работать соответственно — быстро для коротких строк, помедленнее для больших. Вот и все чудеса в решете. А то каждый раз думать, сколько места отводить под имя/фамиилию, приклеивать валидаторы к UI...
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, mrozov, Вы писали:
M>Для начала вычеркиваем фразу про сложное администрирование (2005 express).
Потом вспоминаем, что задачи есть разные и записываем обратно.
M>Потом задумываемся про размеры оверхеда и его реальный вклад.
Крепко задумываемся. А так же задумываемся где мы это дело используем.
M>Потом вспоминаем про удобство единообразного подхода к работе с хранилищами данных.
А так же про необходимость заниматься изнурительным OR маппингом, и вообще про проблемы связанные с поддержкой универсальности.
M>Я лично пришел к выводу, что мне такая штука не нужна даже даром — потому как я буду сомневаться в стабильности ее работы и все равно выберу sql.
Твое право, тогда эта тема не для тебя..
M>А вообще, такие вещи вроде давно уже есть, только мало кто их использует.
Пример?
Я вот сходу могу назвать где их много используют, причем каждый свое:
Omea Reader, Bat, Opera, Outlook... Почему бы тебе не посоветовать этим ребятам использовать SQL Express, Oracle Express или DB2 (тоже как-то на E)?
На первом этапе, естественно, всегда выбирается готовое хранилище, чтобы не забивать себе голову мелочами, но когда выясняется, что готовое хранилище по каким-то параметрам не подходит приходится изобретать что-то свое... Вот каким это "свое" должно быть, и призван выяснить этот топик...
Здравствуйте, AndrewVK, Вы писали:
AVK>Но не до беспредела. У меня на машине 2гига оперативки, и я согласен если БД сожрет лишнюю сотню мег, если при этом она будет работать ощутимо быстрее.
Так ты что, делаешь БД только для себя?
У меня на машине 777 метров, загружены две студии 2005, 3 ворда, outlook, vss. Периодически поднимаются свои приложения в режиме отладки. Слоты для памяти, кончились, официально хрен выпишешь. Janus поднимать на работе боюсь. Не до него, свои бы не тормозили. Так что если лишнюю сотню будет занимать outlook, или icq — я не согласен. IMHO. Одно из бенефитов встроенной базы данных должно быть то, что ты можешь работать с массивом информации с достаточно низким потреблением оперативной памяти.
Здравствуйте, Merle, Вы писали:
M>Блин! Да кто говорит, что сохранять нельзя? Храни пожалуйста, никто не мешает, хоть гигабайт — никаких проблем. M>Даже индекс построить можно по первому килобайту. M>Еще раз спрашиваю, что ты искать-то собрался в B+, в письмах, по ключу такого размера??
Здравствуйте, GlebZ, Вы писали:
GZ>Да я то вполне понимаю(и про ошибочку с like понимаю ). Но наверняка начнутся привязки системы поиск к несвойственным ему полям. Другого пути то нет. Есть поле comments, в который кладут некоторый коментарий. И захотелось программеру сделать по нему поиск. Обычно комментс в районе 200-300 байт(если не null), но один коммент — 2000 кила. Ошибка вывалится то у пользователя, и что делать? Какой нибудь рычаг о том, что структура выходит за пределы индекса нужен. Пуская программер обрабатывает его по своему усмотрению. Но он нужен.
Никакой ошибки не вывалится. Индекс по строке означает ускорение трех типов запросов:
select * from ... where str between "Иванов" and "Петров"
select * from ... where str like "Ива%"
select * from ... where str = "Иванов Иван Иваныч потеплей оделся на ночь"
Во всех остальных случаях будет идти честное сканирование таблицы.
Что же произойдет в случае поиска типа 1? "Обрезанные" ключи сохраняют лексикографическую упорядоченность, за исключением "длинной" части. Ну, давай предположим для упрощения, что у нас ключ длиной всего в 6 символов. С точки зрения этого индекса Авалонов идет до Иванова, а Хунта — после Петрова.
Поэтому Range seek прекрасно пройдет по индексу и никаких проблем не встретит. Поиск с like — точно так же.
Если значение, которое мы ищем, длинее ключа индекса, то предикат распадется на два:
___str_key = "Иванов" AND str = "Иванов Иван Иваныч потеплей оделся на ночь"
Это позволяет выполнить нормальный index seek+bookmark lookup+filter. Первая операция имеет хорошие шансы существенно сократить объем filter.
К тому же собственно bookmark lookup нужен только для тех записей, где длина фактически превышает длину ключа, что вполне соответствует нашей модели: быстро работаем там, где возможно, откатываясь на более медленный алгоритм там, где приходится.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
E>Ну здесь есть разные мнения. Константин Книжник не зря в своих БД shadow copy использует. А он очень обстоятельно, насколько я заметил, к разработке подходит.
У Shadow Copy свои тараканы, например там минимальная гранулярность — страница, если я правильно помню... Хотя для настольных СУБД это может быть и не проблема. С частичным откатом там тоже проблема, если вдруг Save Point-ы понядобятся или, упаси байт, вложенные транзакции..
E>А Redo Only лог позволит транзакции откатывать?
Конечно.. Собственно WAL и Redo Only вовсе не взаимоисключающие понятия. Redo Only — это способ организаци лога WAL — способ работы с логом, означающий что преже чем попасть в основную базу данные обязательно должны оказаться в логе, что гарантирует восстановимость.
Соответственно, при Redo Only логе данные в базу до коммита никогда не попадут и для отката можно просто зачитать предыдущие данные из БД.
При коммите надо будет сбросить все данные в основное хранилище, если используется схема без check-поинтов, или сбросить на диск в лог и перенести в основное хранилище по чек-поинту.
Есть схема Undo Only, когда вся информация сразу пишется в БД, а в лог кладется предыдущая версия соответственно при откате все данные берутся из лога, но эта схема очевидно плоха тем, что в силу WAL данные должны писаться и в лог и в БД параллельно, а это ведет к большим нагрузкам на дисковую подсистему.
В серьезных СУБД сейчас как правило используется схема Undo/Redo. Запись лога представляет собой пару значений старая версия/новая версия. При этом есть возможность Lazy Writer-ом спокойно писать в базу, когда дисковая подсистема свободна и откатить/накотить данные в любой момент в случае сбоя.
Есть так же схема No Redo/No Undo, по сути это Redo Only, но все Redo данные держатся в памяти, а при коммите атомарно сбрасываются на диск в основное хранилище, главная проблема — обеспечить эту атомарность.. Ну и что делать если память закончилась.....
Здравствуйте, AndrewVK, Вы писали:
AVK>Ага, ты еще ТЗ попроси.
ТЗ нет. А вот vision — с удовольствием бы. Тогда было бы более понятно что строим и с кем конкурируем. И вообще границы задачи.
GZ>>>>Только не keyset. Повторюсь, неэффективно. GZ>>И часто ты пользовался именно keyset? AVK>На десктопе часто.
Никогда. Лучше я десять раз перекачаю лишние данные, чем каждый раз обращаться к серваку. А десктопами, особо не занимался.
GZ>>(это ведь только один из курсоров). Логика построения запросов для серверных курсоров достаточно сложная вещь. AVK>Я серверные не использую, я использую клиентские. И здесь речь, ты еще не забыл, о настольной БД. Проблемы серверных БД меня в данном контексте не волнуют, особенно проблемы многопользовательского доступа.
Проблема серверных курсоров лежит в многопользовательском доступе, и только в нем. И больше нигде. Поэтому предлагаю размыть разницу между серверным и клиентским курсором. Тем более что у нас именно встроенная система.
GZ>>А вообще, при тяжелых join именно keyset применим? AVK>Еще как. А что, у тебя с этим какие то проблемы?
Я просто не понял, если ты держишь у себя результат join'a, то есть проекции от него, то каким образом ты его адресуешь? Или это только когда проекция одной таблицы?
AVK>>>Только в том случае, если на уровне БД есть полиморфизм. В реляционных БД никакого полиморфизма нет. GZ>>Запрос подтвержен изменениям. AVK> Каким?
На заключительном этапе мы пытаемся отрефакторить новое приложение так, чтобы пользователь хотя бы чайку при запросе не успел выпить. А достигается это рефакторингом запросов и схемы. А менять приложение в таком случае, не очень приятное занятие.
AVK>Вобщем я не могу понять, что за алгоритм ты имеешь ввиду. Попробуй объяснить его поподробнее.
OK. Несколько прописных истин приведу, для большего понятия:
1. Primary Key — это система получения физического адреса записи по некоторому значению. Физический адрес может быть изменен(например при restore backup, или shrink), поэтому он ни в каком виде не предоставляется пользователю.
2. Нам не нужно какое-то упорядочение ни логических адресов(значений primary key) ни физических. Кластерный индекс по ним не строится(ну можем представить смысл в кластерном индексе основанном на guid). Для кластерного индекса пользователь может использовать любой свой, основанный на B+ индексе.
3. Типов хешей, я знаю по крайней мере 3(это не по функциям, а по типам алгоритмов). Сказать как они называются не могу, давно серьезно этим занимался, если что, ради буквы закона, можно спросить в алгоритмах. Первый — когда работаем по косвенной адресации. Косвенная адресация массива — это простейший тип, h(i)=i. Второй, это когда мы в случае коллизий кладем значение где-то возле коллизии, третий — когда мы в случае коллизии продолжаем хеширование пока не найдем пустое место(собственно, именно этот тип реализован в Net насколько я помню). В данном случае — это первый тип. У нас в значении лежит относительный адрес в хеш-таблице по которому мы можем найти физический. То есть по хеш-функция h(i)=относительный_адрес_страницы+относительный_адрес_значения_физического_указателя_на_строку.
4. Страницы и сегменты адресуются тремя способами. Первый способ — страницы одной таблицы или индекса связаные как двухсвязный список. Мы через IAM находим первую блок, и далее по списку. Второй способ — B tree что-то типа здесь. Третий способ — прямая адресация.
5. Для нахождения нужного row, a) мы получили значение primary key и имя таблицы(или индекса).
b) Нашли в IAM страницу с началом списка hash-таблицы. (1 чтение, скорее всего из буфера)
c) По хеш функции высчитали относительное положение в таблице (относительное положение страницы и относительное положение в страницу).
d) По дереву дошли до нужной страницы.(1<x<n чтений в глубину, вероятнее всего из кэша, и то что 1).
e) Прочитали 8 байтовое значение.
f) Относительно данного значения вычислили страницу где находится данная строка
j) Прочитали страницу
h) Пользуясь списком row в конце страницы и физическим адресом, нашли строку, и ее вернули
6. bitmap — это очень простой индекс. То есть, каждое значение — это либо установленный бит, либо сброшенный бит. Биты пакуются в байты, то есть каждый байт — это 8 значений.
7. Мы содержим в заголовке первой страницы bitmap index с свободными страницами. Ну например, если бит сброшен то в странице есть пустые элементы в которые можно вставить. Ну например, 11101101 — на 4 и 7 страницу можно вставить значение. После этого при вставке находим 4 страницу, находим пустое значение, вставляем физический адрес создаваемой строки, и возвращаем относительный адрес данного элемента который в дальнейшем будет первичным ключом для данной строки. Соответсвенно, смотрим есть ли еще свободные элементы. Если элементов нет, то мы устанавливаем бит, что данная страница полностью занята.
8. Допустим мы отведем в заголовке под индекс — 128 байт. Как результат, у нас получится что индекс управляет 128*8=1024 страницы. Каждая страница содержит — 1024 физических адреса. То есть, с помощью 128 байт мы держим 1 миллион записей. Если мы переходим через 1 миллион записей, то создаем еще битмап индекс в 128 байт и привязываем его через двухстороннюю очередь.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Могу. Но вопрос остается прежним — что делать при модификациях? S>>Перераспределение при переполнении но только части страниц.
AVK>А что делать с внешними ключами?
S>> Хотя индекс по хэшам длинных индексов имхо выгодней, а для небольших по размеру ключей выигрыш для хэш таблиц небольшой , учитывая кэширования верхних страниц индекса.
AVK>Он выгоднее в памяти. А вот работающий алгоритм для диска я пока не услышал.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, GlebZ, Вы писали:
AVK>>>На практике именно буква I самая заковыристая. GZ>>I очень заковыристая, в случае если у тебя модель данных и объектная модель не слишком совпадают. Фактически, уровень оптимистических транзакций вполне должно хватить за глаза.
AVK>Она всегда заковыристая. Я, в свое время, много с этим намаялся. Там чисто логические проблемы, которые до сих пор универсально не решены нигде.
+1. Правда я не видел достойных механизмов (кроме своих конечно).
AVK>>>ИМХО это уже чисто прикладная логика. Впрочем можно вынести на уровень БД, но тогда нужны вложенные транзакции или хотя бы сейвпоинты. GZ>>Зачем? Не нужны. У тебя есть состояние в памяти. А сохранять его атомарно.
AVK>Это и есть пессимистические транзакции. Но до редактирования сообщения может быть проведен ряд операций, откатывать которые нежелательно.
Что то тут мы похоже расходимся в терминах:
Оптимистическая транзакция — транзакция откатывается в случаях конфликтов сама. Обычно построена на нежестких блокировках, типа версий, или прежних состояний. Оптимистической она называется потому как эффективна только в случае низкой конкуренции за ресурсы.
Пессимистимистическая транзакция — транзакция старается обеспечить свою успешность за счет других транзакций. Пессимистеческой называется потому как предполагает что существует высокая конкуренция за ресурсы.
Здравствуйте, Cyberax, Вы писали:
>> Ты имеешь ввиду наследство Yaffil? Это совсем не то. C>Нет, я имею в виду FireBird Embedded
Это оно и есть. Совсем не интересно. Это обычный SQL сервер.
>> Аргументы? C>In-proc если к базе должен иметь доступ только один процесс C>одновременно. В противном случае — outproc.
А зачем доступ к десктопной базе нескольких процессов? Собственно отсуствие онного есть одна из предпосылок отличий проектных решений от классического SQL-сервера.
>> C>Как обычно. >> SQL? C>SQL, Linq,
SQL и LINQ это две очень большие разницы.
C> навигационный доступ. Не вижу причин делать что-то отличное C>от обычных БД.
Причина простая — для SQL необходим парсер, интерпретатор и очень сложный оптимизатор. Это, помимо объема работы, еще и лишний оверхед.
>>> > 5) Контроль на уровне БД. Вобще разграничение функций между движком БД и >>> > прикладным кодом >> C>Как обычно. >> Нету никакого как обычно. В разных решениях по разному. C>Имею в виду, что нет смысла изобретать что-то новое.
А что конкретно лучше всего подойдет из старого?
>> C>Скопировать файлы базы и dll-ки драйвера (для inproc). >> Алгоритм деплоймента прикладных БД в двтжек, а не деплоймент самого движка. C>Так я и говорю про деплоймент баз — в строке соединения просто C>прописывается путь до файла БД. Соответственно, для деплоймента базы C>просто нужно положить куда-нибудь файл.
Блин, еще раз. Есть некая система Х — ей нужно создать/обновить структуру БД XY, ей потребной. Весь вопрос в том как это сделать.
>> C>А вообще, все должно быть как можно проще и легковеснее. >> И при этом ты советуешь SQL, out of process и DDL. Нестыковочка выходит. C>А что, SQL уже подразумевает SQL Server?
SQL подразумевает немаленькие затраты на его парсинг и интерпретацию.
C>SQLite имеет SQL-движок размером в несколько сотен килобайт, в FireBird C>около мегабайта.
Здравствуйте, AndrewVK, Вы писали:
AVK>1) Оптимистичные или пессимистичные?
А какая разница, если БД однопользовательская?
AVK>2) Нужны ли вложенные транзакции?
Нет.
AVK>3) Можно ли обойтись без транзакций вовсе или вынести их из движка БД на уровень библиотеки?
Нет, Атомарность изменений и устойчивость, пусть лучше БД обеспечивает.
Здравствуйте, Merle, Вы писали:
M>Тут не ACID, тут A. И, в отличии от больших БД, здесь можно ограничиться только Redo Only логом.
А если транзакции пессимистические, то лог вобще можно на диск не скидывать.
M>I здесь не нужно, в силу того, что БД однопользовательская,
+1
M> D здесь тоже обеспечит аккуртная реализация логгирования, C — это отдельная тема для обсуждения, не думаю что весь набор больших БД здесь сильно необходим...
Здравствуйте, Cyberax, Вы писали:
>> О транзакциях: >> 1) Оптимистичные или пессимистичные? C>Зависит от потребностей и возможностей.
Если не достаточно тех рамок, что я описал, то пусть, для примера, это будет почтовый клиент.
>> 3) Можно ли обойтись без транзакций вовсе или вынести их из движка БД на >> уровень библиотеки? C>Лучше не надо. Транзакции замечательно на уровне БД живут,
Не так уж и замечательно.
C> и прикладные транзакции очень удобно делать поверх транзакций в БД.
А зачем нам две механики транзакций, если можно обойтись одной?
Здравствуйте, Merle, Вы писали:
AVK>>1) Оптимистичные или пессимистичные? M>А какая разница, если БД однопользовательская?
Разница в необходимости скидывать на диск лог.
AVK>>3) Можно ли обойтись без транзакций вовсе или вынести их из движка БД на уровень библиотеки? M>Нет, Атомарность изменений и устойчивость, пусть лучше БД обеспечивает.
Так БД в in process варианте у нас ничуть не отличается от прикладного кода. Ладно, перефразирую вопрос — имеет ли смысл делать транзакции подстраиваемыми под конкретную задачу или жестко вшивать их в движек БД?
Здравствуйте, Cyberax, Вы писали:
>> C> и прикладные транзакции очень удобно делать поверх транзакций в БД. >> А зачем нам две механики транзакций, если можно обойтись одной? C>Я имею в виду, что транзакции в приложении являются "обертками" для C>транзакций в БД.
Здравствуйте, eao197, Вы писали:
E>Доступ к БД из разных приложений одновременно. Хотелось бы иметь, таки.
Это зацепит за собой целый грузовик проблем (особенно меня пугает необходимость параллельных транзакций) и в результате мы придем к теперешним SQL-серверам. Поэтому предлагаю искуственно ввести ограничение на однопользовательский режим.
E> Хотя бы в режиме: один может и читать и писать, а остальные хотя бы читать.
Если I = Read Commited (для полной гарантии отсутствия snapshot too old), то вполне возможно. Но! Возникает вопрос межпроцессной коммуникации, сериализации, протоколов обмена, а обеспечение типизированного доступа усложняется. Мне кажется, это лучше сделать ввиде отдельного, независимого от движка БД слоя, используемого только при необходимости.
E> Объясню почему: иногда какая-то программа крутиться постоянно, остановить ее нет возможности. Но вот глянуть, чтоже у него внутри базы твориться бывает необходимо. Обычно это связано с сохранением в БД ошибочных данных или с ошибочной обработкой корректных данных.
Но в десктопных приложениях очень часто используется кеш в памяти (прикладной!). Если ты напрямую влезешь в БД, то автоматом пролетишь мимо него. Тебе не кажется, что подобные запросы должны проходить все равно через прикладной слой?
Здравствуйте, GlebZ, Вы писали:
AVK>>На практике именно буква I самая заковыристая. GZ>I очень заковыристая, в случае если у тебя модель данных и объектная модель не слишком совпадают. Фактически, уровень оптимистических транзакций вполне должно хватить за глаза.
Она всегда заковыристая. Я, в свое время, много с этим намаялся. Там чисто логические проблемы, которые до сих пор универсально не решены нигде.
AVK>>ИМХО это уже чисто прикладная логика. Впрочем можно вынести на уровень БД, но тогда нужны вложенные транзакции или хотя бы сейвпоинты. GZ>Зачем? Не нужны. У тебя есть состояние в памяти. А сохранять его атомарно.
Это и есть пессимистические транзакции. Но до редактирования сообщения может быть проведен ряд операций, откатывать которые нежелательно.
Здравствуйте, WoldemaR, Вы писали:
WR>Нужны не триггеры а хуки. Нужно чтобы я в одном приложении мог пасти на изменения, определённую ветку данных (как папку в файловой системе) сделанные в другом приложении. Т.е. нужен калбэк-интерфейс.
Нет, этим должен сервер приложений занимаеться. Не дело базе данных клиентов оповещать.
... << RSDN@Home 1.2.0 alpha rev. 648>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, eao197, Вы писали:
E>Да здесь то же самое. Представь, что в ссылки в индексах хранят не прямой адрес страницы, а ее идентификатор. А по идентификатору через специальную relocation table ты находишь адрес. Тогда, при необходимости перезаписи страницы БД (индекс это или страница с объектами/строками/туплами), ты просто записываешь страницу в новое место и правишь ссылку на нее в memory-relocation-table. При фиксации транзакции сбрасываешь memory-relocation-table на диск. И все. Сложность только в атомарности изменения relocation table.
При этом учитывашь что у тебя получается очень высокая дефрагментация БД. Не знаю как сейчас, но раньше Interbase работал по такому принципу.
И обмены с БД идут объектами trx_info_t. Вот trx_info_t я и называю объектом.
E>>Ты не понял полностью. Нет перезаписи страницы.
AVK>Вот и плохо что нет. Пойми простую вещь — на диск все равно меньше 512 байти не запишешь, даже если тебе всего 8 байт ссылки надо поправить. Соответственно править ссылки в 3 страницах будет медленнее, нежели перезаписать содержимое одной единственной. А таблица пересчета, спасая от правки ссылок в страницах, привносит свои проблемы.
Это я понимаю. Но таблица пересчета кроме проблем дает и преимущества. Например, с ее помощью избавляешься от проблемы фрагментации БД.
AVK>Тем не менее медленнее чем без нее.
Ну это не серьезно, право слово.
Обращение:
a[i]
конечно же медленне, чем
a[ t[i] ]
но по сравнению со скоростями дисковой подсистемы...
E>> И достаточно компактно.
AVK>Пусть страница 8К. Размер БД 10Г. Итого размер таблицы пересчета = 10Г / 8К * 16 = 20М. Считаешь 20 мег это немного?
Почему на 16 умножается? Страница 8K -- это 2^13 байт. Если номер страницы будет 4-х байтовый (т.е. использовать в качестве адресации не смещения странц, а их порядковые номера), то всего объем БД может составлять 2^32 * 2^13 = 2^45 = 32Tb.
Значит для 16Gb БД потребуется 2^22 страниц. Для таблицы пересчета потребуется 2^24 = 8M. Если я не ошибся в подсчетах.
И это при том, что всю таблицу пересчета в ОП можно не хранить, а подгружать сегменами по мере надобности. С учетом фактора локальности ссылок это не должно быть большой проблемой.
Но здесь следовало бы поэкспериментировать на прототипах с замерами производительности.
AVK>Плохо смотришь. Сбой в таблице пересчета абсолютно критичен. Следовательно, внося эту таблицу, мы снижаем надежность системы в целом на вероятность сбоя в таблице пересчета.
Надежность фиксации таблицы пересчета конечно же важна. Но подумай сам, неужели надежность фиксации WAL должна быть ниже? Представь, что ты записал WAL, после чего начал коммитить страницы в основной файл БД. Произошел сбой и БД пришлось восстанавливать путем доката WAL. Но если что-то в WAL запортилось, и ты этого не смог обнаружить, то бяка все равно случится. Механизм фиксации транзакций должен быть по-определению надежным. В меру возможности.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Sinclair, Вы писали:
S>>Рекомендую почитать в SQL BOL про организацию файлов MDF.
AVK>А там это описано? здесь
S>>К примеру, varchar(max) и varbinary(max) — это просто the must для этой потенциальной встраиваемой БД. Потому что не стоит парить разработчика выбором длины поля типа string и вопросами перехода на Memo.
AVK>+1000!
Только это сильно усложнит систему хранения и операций с ним. Да и статистику, если будешь делать, также.
GZ>Для MSSQL varchar(max) image e.t.c. лежат в отдельных сегментах. Oracle умеет запись класть на несколько страниц. Разница есть.
MSSQL тоже умеет, так что разницы нет. Это он специально для max-типов отдельное хранилище держит, что вообщем разумно и совершенно не мешает сделать так же. А вот если сумма обычных varchar-ов вылезает за размер страницы, то он совершенно спокойно резервирует дополнительную страницу под это дело и кладет хвостик туда, проставляя ссылочку.
GZ>Как результат, у нас нет уверености что мы сможем проиндексировать строки с неограниченной переменной длиной(как предлагал Sinclair).
Во-первых Тоха не предлагал индексировать строки с различной переменной длинной, он предлагал их хранить и не париться над размером. Во-вторых я не вижу почему бы не индексировать только первый килобайт, если строка слишком большая, все равно ключ текст из середины сравнивать не умеет, и сравнение таких больших кусков очень большая экзотика...
M>Для начала вычеркиваем фразу про сложное администрирование (2005 express). >Потом вспоминаем, что задачи есть разные и записываем обратно.
? Я понимаю, что есть задачи, для которых юконом воспользоваться нельзя. Но при чем тут сложности с администрированием??? Или ты еще просто не использовал эту штуку?
M>Твое право, тогда эта тема не для тебя..
+1
Просто один знакомый этими вещами заморачивается, вот и заглянул.
M>Я вот сходу могу назвать где их много используют
FAT
M>На первом этапе, естественно, всегда выбирается готовое хранилище, чтобы не забивать себе голову мелочами, но когда выясняется, что готовое хранилище по каким-то параметрам не подходит приходится изобретать что-то свое... Вот каким это "свое" должно быть, и призван выяснить этот топик...
Боюсь, что "приходится изобретать что-то свое" прямо противоречит самому смыслу топика.
Ежели мы думаем над универсальностью, то нужна серьезная теоретическая база. На коленках это делать бесполезно. Труд огромный, а выигрыш -ну.... не такой уж огромный.
Здравствуйте, AndrewVK, Вы писали:
GZ>>Не-а. Ты не о том. Там редактирование различных запросов происходят по интересной схеме. Что то типа: GZ>>
GZ>>var v=from c in db.bla select c;
GZ>>var v1=from c1 in db.bla1, c2 in v where c1.id=c2.id select c2;
GZ>>var res=v1.ToList();
GZ>>
GZ>>У меня есть сомнения в оптимальности такого подхода. Или надо будет писать логический оптимизатор запросов.
AVK>И при чем здесь функциональная форма? Ты декларативную привел.
Перепиши в функциональных терминах, будет то же самое. Проблема существует.
GZ>>a)Логика выполнения запроса в режиме на каждый row — достаточно сложна. При использовании проекций, каждый раз нам придется его выполнять сново, или удерживать результаты части запроса. GZ>>б) Или в запросе используются данные, получая key без данных, мы должны перечитывать их сново. GZ>>Моя аргументация понятна? AVK>Неа. Я уже совершенно потерялся и не могу понять, что ты хочешь доказать.
Что keyset не нужен.
GZ>>Вопрос: GZ>>Примерная структура: GZ>>1 уровень. Файл, сегменты, страницы. GZ>>2 уровень. Типизированные данные, то бишь таблицы или отношения (должны иметь информацию о типах), индексы. GZ>>3 уровень. Собственно он и есть конечная цель. Объекты и типизированные списки объектов(или tuples, по фиг). То есть то, чем пользуется пользователь.(должна иметь свою информацию о типах). GZ>>Я правильно тебя понял?
AVK>Примерно.
Отлично, сразу уточняющий вопрос:
При трансформации из записей таблиц в объекты с помощью операции проекции мы теряем информацию о том как этот объект живет на втором уровне. Как эту проблему решать?
AVK>Не, проблема с хеш-индексом не в этом, а в том, что при модификации такого индекса он ведет себя не очень хорошо для того чтобы хранить его на диске. Иы можешь предложить алгоритм, чтобы количество дисковых операций при добавлении и удалении значений было сопоставимым с В+ индексом?
Легко. Но надо сначало со структурой хранения. Хеш функция ведь должна по чему-то адресоваться.
Здравствуйте, Sinclair, Вы писали:
E>>Интересно, а каким боком все это относится к моему сообщению? S>Таким, что не надо сидеть и гадать, что дешевле — таблицы пересчета или там что еще. Ты все же сходи, почитай, как дяди делают. Твои рассуждения про замедление a[t[i]] по срввнению с a[i] — извини, лепет. Андрей говорит о том, что для выборки данных в твоем варианте надо сделать два обращения к диску — одно для t[i], и второе для a[t[i]].
В первый раз. При последующих обращениях t[i] уже будет в памяти. В продвинутом случае в специальном хранилище для t, в тривиальном случае -- в кэше БД.
Или ты знаешь БД, которые вообще без кэша работают?
E>>К слову, моя система хранения как раз и создавалась для того, чтобы хранить объекты, динамически изменяющие свой размер (вроде std::string, std::vector, std::list и пр.). S>Я мало знаю про твою систему хранения, зато знаю, что у Юкона мажорный номер версии равен 9. Эти парни уже пятнадцать лет полируют глюкало, основываясь на очень подробных данных о фактическом использовании, передовых теоретических разработках, и глубоких знаниях нижележащих технологий. Я слежу за эволюцией их стораджа начиная с версии 6.5. И я очень сомневаюсь, что кустарные поделки смогут сильно их превзойти на аналогичном поле.
Опаньки, а где я противопоставлял свою систему Юкону? Может напомнишь?
И по поводу кустарных поделок -- скажи это AndrewVK, а то он какую-то тему про кустарные настольные БД затеял, даже странно как-то.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, stalcer, Вы писали:
AVK>>К тебе тот же вопрос — как обеспечить малое количество дисковых операций при добавлении или удалении элементов? Стандартная техника с бакетами, используемая в нетовских хештаблицах для диска мало подходит.
S>А какая разница?
Разница самая обыкновенная — для того чтобы работала хеш-таблица хеши должны быть линейно упорядоченны. Как обеспечивается это в памяти я знаю, а вот как обеспечить это на диске пока не ясно.
Здравствуйте, GlebZ, Вы писали:
GZ> Для кластерного индекса пользователь может использовать любой свой, основанный на B+ индексе.
Так ли велик будет выигрыш от приседания вокруг хэш-таблицы, если все равно надо поддерживать два типа индексов, причем хэш-таблица какая-то не очень тривиальная получается?
Здравствуйте, Serginio1, Вы писали:
S> При фиксированнолм размере удовольствие бесплатное. Всё от задач.
Во-во, а задачи такие, что фиксированный размер только по большим праздникам.
S>А чем тебе не нравится Extendible Hashing.
требует наличия в основной памяти справочного дерева.
S>До миллиона элементов вполне приемлемая технология.
А после миллиона что делать?
S> В этот размер умещается большинство справочников.
А не справочников? А что делать если не уместится?
Проблема в том что такой подход не обладает должной универсальностью и требует довольно серьезного расхода ресурсов, что в настольной системе вряд ли можно себе позволить.
Здравствуйте, Serginio1, Вы писали:
S>Что бы замять этот разговор то в зависимости от строение бд можно придумать строение ПК так, чтобы по нему можно было найти физический адрес.
Нельзя, потому что физический адрес меняется при расщеплении страницы и придется все FK в базе отыскивать и править.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>Что бы замять этот разговор то в зависимости от строение бд можно придумать строение ПК так, чтобы по нему можно было найти физический адрес.
AVK>Нельзя, потому что физический адрес меняется при расщеплении страницы и придется все FK в базе отыскивать и править.
Это еще при условии, что они все по FK лежат. А могут и без FK лежать
Здравствуйте, GlebZ, Вы писали: GZ>Извиняюсь, не могу сдержаться. GZ>Во первых ты говоришь не о доступе как таковом, а о поиске.
Ну, в принципе да. У тебя есть альтернативное определение термина "доступ"? GZ>Что является лишь частью доступа. Во вторых, всех так на курсоры тянем что у меня есть сомнения в декларативном доступе. А тянет всех потому как нельзя в sql запросе указывать сложную логику зависящую от состояния читаемого объекта(даешь в sql делегаты, хотя и они могут не спасать).
Гм. В этом месте не понял. SQL предназначен для того, чтобы выполнять операции с данными. Никаких объектов там нет. Есть кортежи. При этом сложную логику, зависящую от состояния кортежа, в SQL вполне можно использовать. Хотя, конечно же, применение индексов существенно затрудняется сложными выражениями (читай — делается невозможным). Низкая производительность самих по себе выражений лежит исключительно на совести реализаторов — никто не мешает в движке SQL скомпилировать выражение 2*a*a + SQRT(b) / с прямо в нативный код, а не париться с интерпретацией. GZ>В третьих, sql так построен, что дальше навигации с курсором особо не уйдешь.
Вина SQL в том, что это диалоговый язык. Убил бы того, кто это придумал. Результатом стейтмента Select должна быть не отправка резулт сета в трубу, а выражение реляционного типа.
Что-то вроде табличной переменной в MS SQL, только без выполнения запроса. Чтобы можно было делать так:
declare @a (id int, code int)
set @a = select id, type from sysobjects
if not @type is null
set @a = select * from @a where type = @type
return @a
Все как в функциональных языках — берем ленивые выражения, строим из них другие и т.п. И только когда нам наконец понадобились сами данные, отдаем запрос на выполнение. GZ>В пятых, у меня как бич получается, что на каждом проекте мне приходится в той. или иной мере реализовывать редактор sql запросов.
А это ты к чему? Сложности редактирования сами по себе слабо связаны с SQL. Их суть в том, что сам запрос надо рассматривать как объект. Что, впрочем, вполне противоречит принятому в SQL идиотизму с желанием как можно быстрее перейти "от слов к делу", точнее от текста запроса к табличке с данными. GZ>В шестых, весьма удобно отойти от отношения как такового, а перейти к навигации в определенных случаях. Например у тебя форма. Обычно данные в такой форме есть дерево по которому в случае навигационного доступа было бы удобно бегать.
Это я тоже не очень понимаю. Навигация суть частный случай поиска по первичному ключу.
S>>>А мы кстати обсуждаем настольные базы данных, в которых технические проблемы организации навигационного доступа совсем не такие, как в сетевой многопользовательской СУБД. GZ>Ага, там единственная проблема, она не sql, и под sql никак не клеится.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Sinclair, Вы писали:
S>>Но навигация вредит всему этому. Она слишком императивна, и требует от разработчика слишком точного представления о том, как именно устроены данные, с которыми он работает. GZ>Вопрос 1 — чем может помешать оптимизатору навигационный доступ в локальной системе?
Как это чем? Навигация — это физический план запроса. Это императивная конструкция, которая оперирует понятием ссылок. Навигация подменяет смысл операции ее выполнением. В результате эксплуатации навигация превращается в ритуал, которому тупо следует приложение, вместо того, чтобы отбросить все ненужное
GZ>Я согласен на иное, что оптимизатор мешается и слишком избыточен для навигационного доступа.
В тех случаях, когда навигационный доступ соответствует оптимальному плану запроса это так. Но как только оптимальность перестает быть действительной, только оптимизатор имеет шанс выбрать альтернативный план. GZ>Вопрос 2. Такое впечатление что ты когда говоришь о навигационном доступе, говоришь о проходах на физическом уровне.
Конечно. GZ>Это действительно, очень нехорошо. Но если говорить о проходах на логическом уровне (который потом уже будет трансформирован в физический) то проблем не вижу.
А я вот не вижу, как это так можно сделать навигацию на "логическом уровне".
Ну вот простейший пример: Допустим, у нас есть модель "заказы и позиции". Эта модель очень удобна, если нам нужно найти заказы конкретного заказчика (Customer.Orders) и распечатать сами заказы (Order.Items). Но как только у нас появляется задача выбрать всех, кто купил слона, приходится писать вот так:
foreach(Customer с in AllCustomers)
foreach(Order o in c.Orders)
foreach(Item i in o.Items)
if (i.Good = elephant)
yield return c;
Мы выбрали конкретный путь навигации. Некому решить, что лучше сканировать сначала — кастомеров или айтемы.
Можно попробовать схитрить:
foreach(Item i in AllItems)
if (i.Good = elephant)
yield return i.Order.Customer;
И скормить результат в оператор distinct. Но заранее неизвестно, будет ли это эффективнее.
Все, упес пипиндур. Для того, чтобы сделать динамический выбор возможным, нужно отказаться от принудительного характера foreach, и вместо этого сформулировать предикат, а не способ его выполнения.
Я не против того, чтобы предикат был записан в форме distinct Item.Order.Customer where Item.Good = elephant. Но это — не навигация. Это просто другое представление ассоциативного запроса.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AndrewVK, Вы писали:
AVK>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов.
Выглядит она примерно так: BerkleyDB
MySQL с InnoDB в качестве движка тоже подойдет — он умеет встраиваться inproc.
Более конкретный список вопросов: AVK>1) in process или out of process?
inproc лучше по совокупности:
1) Нет потерь на межпроцессное взаимодействие (замедление до 10 раз при прокачке больших объемов данных)
2) Проще установка и администрирование приложения, компонентом которого является БД.
AVK>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc Не принципиально. Варианты BTree используют все, кластерный индекс необходим но встречается в inproc-решениях редко, как бить на файлы в большинстве задач пофиг (чем тупее тем лучше — например, файл на таблицу). Еще прикольно, но не необходимо, иметь хэштаблицы. В BerkleyDB это все есть.
AVK>3) Описание метаданных
В заголовке файла таблицы.
Глобальные метаданные нафиг не нужны для встроенной в приложение БД. С ними ни жарко, ни холодно. Если очень надо, их можно XML-схемой описатьи рядом положить.
AVK>4) Способ формирования запросов
ISAM и интерпретатор тупого SQL или другого простого способа формировать запросы. Хранимые процедуры не нужны для inproc БД.
AVK>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
Транзакции нужны. Доступ из множества процессов — бывает полезен, но можно обойтись без него.
AVK>6) Алгоримты деплоймента На совесть программиста. Для встроенной БД, которую я здесь описываю, это несложно.
Собственно, берем BerkleyDB и начинаем радоваться жизни.
Здравствуйте, Belsen, Вы писали:
B>А в пределе мечтаний, конечно хотелось бы, что бы количество загружаемых в запросе данных расчитывалось в компайл-тайме анализом кода, который будет эти данные использовать.
А почему бы тогда не захотеть, что бы сами данные были вкомпилированы в код. Тогда можно было бы избежать использования БД в рантайме вообще.
Здравствуйте, GlebZ, Вы писали:
AVK>>Судя по всему, кто хотел что то сказать, тот уже высказался. Посему всем спасибо. Заинтересованные в дальнейшей проработке концепции пишите мне на avk (собака) rsdn.ru. GZ>Безумству храбрых поем мы песню. GZ>Что-то я думал что все заглохло и пропало. Обычно когда человек замысливал такую вещь, его тут же отсылали к литературе и готовым образцам. После чего он как-то пропадал. Не ожидал.
Наоборот, напоминает афоризм: "Послушай женщину и сделай наоборот".
А толпа, как говаривал один известный деятель XX-го века -- она как женщина, любит силу
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Когда то давно, когда PC только появлялись, было такое явление как настольные СУБД. Потом их практически вытеснили SQL-сервера, и если они и есть где, то это в основном развитие старых продуктов.
SQL-сервера это конечно здорово, однако по прежнему есть ряд применений, для которых их навороты не нужны, равно как не нужен оверхед, связанный с многопользовательским доступом и сложное администрирование.
Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов. Более конкретный список вопросов:
1) in process или out of process?
2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc
3) Описание метаданных
4) Способ формирования запросов
5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
6) Алгоримты деплоймента
Здравствуйте, AndrewVK, Вы писали:
AVK>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc
Индексы B+ Tree, возможно со своими оптимизациями. Один файл на базу хотя возможно более хитрые варианты, тут надо от задачи плясать.
AVK>4) Способ формирования запросов
Не SQL, наверное Linq лучший вариант, чтобы с точки зрения разработчика на обычном ЯП все было прозрачно...
AVK>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
БД должна брать на себя заботу по бакапу, восстановлению, и слежению за согласованностью внутри себя, все остальное запота прикладного кода.
Здравствуйте, Merle, Вы писали:
AVK>>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом M>БД должна брать на себя заботу по бакапу, восстановлению, и слежению за согласованностью внутри себя, все остальное запота прикладного кода.
Вопрос как раз в согласованности. Какого уровня констрейнты должны быть?
Здравствуйте, Cyberax, Вы писали:
C>AndrewVK wrote: >> Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД >> с учетом сужения класса решаемых задач и использования новых технологий >> и подходов. C>Как FireBird
>> 1) in process или out of process? C>Оба варианта.
По моему лучше InProc — меньше оверхеда на взаимодействие с сервером. Очень не часто встречается одновременное юзание десктопной БД разными клиентами . А для однопользовательских вещей лишние тормоза ни к чему. >> 2) Физическая структура хранения на диске — алгоритмы, разбиение на >> файлы etc C>Один файл на базу.
Не факт.
>> 3) Описание метаданных >> 4) Способ формирования запросов C>Как обычно.
Как обычно у кого?
>> 5) Контроль на уровне БД. Вобще разграничение функций между движком БД и >> прикладным кодом C>Как обычно.
Опять же у кого?
>> 6) Алгоримты деплоймента C>Скопировать файлы базы и dll-ки драйвера (для inproc).
C>А вообще, все должно быть как можно проще и легковеснее.
AndrewVK wrote: >> > с учетом сужения класса решаемых задач и использования новых технологий >> > и подходов. > C>Как FireBird > Ты имеешь ввиду наследство Yaffil? Это совсем не то.
Нет, я имею в виду FireBird Embedded — это несколько DLLок общим объемом
в пару мегабайт. Представляют собой версию FireBird (наследник
InterBase) без сетевого стека.
http://firebird.sourceforge.net/
>> > 1) in process или out of process? > C>Оба варианта. > Аргументы?
In-proc если к базе должен иметь доступ только один процесс
одновременно. В противном случае — outproc.
>> > 2) Физическая структура хранения на диске — алгоритмы, разбиение на >> > файлы etc > C>Один файл на базу. > Аргументы?
Проще администрирование.
> C>Как обычно. > SQL?
SQL, Linq, навигационный доступ. Не вижу причин делать что-то отличное
от обычных БД.
>> > 5) Контроль на уровне БД. Вобще разграничение функций между движком БД и >> > прикладным кодом > C>Как обычно. > Нету никакого как обычно. В разных решениях по разному.
Имею в виду, что нет смысла изобретать что-то новое.
>> > 6) Алгоримты деплоймента > C>Скопировать файлы базы и dll-ки драйвера (для inproc). > Алгоритм деплоймента прикладных БД в двтжек, а не деплоймент самого движка.
Так я и говорю про деплоймент баз — в строке соединения просто
прописывается путь до файла БД. Соответственно, для деплоймента базы
просто нужно положить куда-нибудь файл.
> C>А вообще, все должно быть как можно проще и легковеснее. > И при этом ты советуешь SQL, out of process и DDL. Нестыковочка выходит.
А что, SQL уже подразумевает SQL Server?
SQLite имеет SQL-движок размером в несколько сотен килобайт, в FireBird
около мегабайта. Кстати, даже в Outlook'е есть реализация SQL-подобного
языка запросов.
Здравствуйте, AndrewVK, Вы писали:
AVK>Когда то давно, когда PC только появлялись, было такое явление как настольные СУБД. Потом их практически вытеснили SQL-сервера, и если они и есть где, то это в основном развитие старых продуктов. AVK>SQL-сервера это конечно здорово, однако по прежнему есть ряд применений, для которых их навороты не нужны, равно как не нужен оверхед, связанный с многопользовательским доступом и сложное администрирование. AVK>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов. Более конкретный список вопросов: AVK>1) in process или out of process?
Для однопользовательской INPROC для многопользовательской outproc, хотя так как все ограничено одним хостом можно обойтись только inproc с SHARED объектами разграничения доступа. AVK>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc
Варианты
1. Один файл но большой —
преимущества: простота распространения
недостатки: все намешано в кучу, появляються длинные Seek при чтении поиске данных что ни есть гуд.
2. Много файловая БД
а) один файл на таблицу
б) один файл на все данные
С индексами тоже самое
преимущества: можно оптимизировать файлы на предмет подгонки размера страницы под конкретные данные — меньше оверхеда на пустоту,
недостатки: Проблемы с поддержкой кучи файлов, больше используемыъ объектов ядра
Способ организации файла зависит от того по какому пути пойдем, правда в любом случае мимо B+ деревьев не пройдем, да и страничная организация данных тоже никуда не денеться. AVK>3) Описание метаданных
1. DDL — чтобы иметь текстовые определения БД
2. Метаданные в формате БД храняться в самой схеме данных БД или же лежат отдельно — как вариант отдельным файлом — описателем БД.
Зависит от того что мы хотим получить. AVK>4) Способ формирования запросов
SQL или объектные запросы можно вообще обойтись без запросов если делать сетевую БД AVK>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
ACID поддержка транзакционности как минимум с возможностью отката в случае чего. AVK>6) Алгоримты деплоймента
копирование по месту
О первичных ключах:
1) Допустимо ли требование обязательного наличия первичного ключа?
2) Допустимо ли требование несоставного первичного ключа?
3) Допустимо ли требование первичного ключа определенного типа?
4) Допустимо ли требование первичного ключа типа GUID?
О расширяемости:
Что должно быть расширяемо в сабже?
О keysets:
1) Допустимо ли встраивание этой механики в движек БД.
2) Достаточно ли самого простого варианта, или нужна возможность подкрузки в кейсет части данных?
3) Нужна ли многостадийная загрузка или подгрузка в 2 стадии — кейсет и остальные данные? Или может еще какой вариант?
О запросах подробнее:
1) Необходим ли SQL или любой другой текстовый декларативный язык запросов?
2) Что лучше — выборки или навигационный способ(курсоры).
3) Что лучше — декларативный sql-like синтаксис или функциональный стиль?
О метаданных:
1) Допустим ли отказ от специфичных для БД метаданных в пользу метаданных, встроенных в платформу?
2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД?
3) Должны ли типы хранится в БД вместе с данными?
О деплойменте:
Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек?
Какие еще аспекты БД было бы интересно рассмотреть с точки зрения описанной задачи?
Здравствуйте, Merle, Вы писали:
AVK>>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc M>Индексы B+ Tree, возможно со своими оптимизациями. Один файл на базу хотя возможно более хитрые варианты, тут надо от задачи плясать.
Не уверен, что это хорошее требование к «настольным» СУБД, поскольку очень усложняет xcopy — распространение, а от такой СУБД очень хотелось бы такой возможности — для простоты распространения и развёртывания, для удобства переноса, … то есть для устранения сложных администраторских действий.
AVK>>4) Способ формирования запросов M>Не SQL, наверное Linq лучший вариант, чтобы с точки зрения разработчика на обычном ЯП все было прозрачно...
+1
AVK>>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом M>БД должна брать на себя заботу по бакапу, восстановлению, и слежению за согласованностью внутри себя, все остальное запота прикладного кода.
Остальное: это что имеется в виду
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, migel, Вы писали:
M>Для однопользовательской INPROC для многопользовательской outproc, хотя так как все ограничено одним хостом можно обойтись только inproc с SHARED объектами разграничения доступа.
Сразу оговорюсь, если это непонятно из исходного поста — речь об однопользовательской БД. Иначе получится yet another SQL server.
AVK>>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc M>Варианты M>1. Один файл но большой — M> преимущества: простота распространения M> недостатки: все намешано в кучу, появляються длинные Seek при чтении поиске данных что ни есть гуд.
Привод головок у винта все равно один, так что много файлов от длинных сиков не спасают.
M>2. Много файловая БД M> а) один файл на таблицу M> б) один файл на все данные M> С индексами тоже самое M> преимущества: можно оптимизировать файлы на предмет подгонки размера страницы под конкретные данные — меньше оверхеда на пустоту, M> недостатки: Проблемы с поддержкой кучи файлов, больше используемыъ объектов ядра
Самое непонятное — что делать если какой то файл потерялся?
AVK>>3) Описание метаданных M>1. DDL — чтобы иметь текстовые определения БД
А зачем?
M>2. Метаданные в формате БД храняться в самой схеме данных БД или же лежат отдельно — как вариант отдельным файлом — описателем БД.
Как определять факт несоответствия?
AVK>>4) Способ формирования запросов M>SQL или объектные запросы можно вообще обойтись без запросов если делать сетевую БД
А зачем SQL?
AVK>>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом M>ACID поддержка транзакционности как минимум с возможностью отката в случае чего.
Зачем, если БД однопользовательская?
AVK>>6) Алгоримты деплоймента M>копирование по месту
Здравствуйте, AndrewVK, Вы писали:
AVK>О первичных ключах: AVK>1) Допустимо ли требование обязательного наличия первичного ключа? AVK>2) Допустимо ли требование несоставного первичного ключа? AVK>3) Допустимо ли требование первичного ключа определенного типа? AVK>4) Допустимо ли требование первичного ключа типа GUID?
Каждое, по-отдельности, ИМХО, недопустимо, поскольку влечёт за собой перепроектирование готовой уже схемы данных или привязку создаваемой вновь к способу хранения. Я бы сказал, что допустим строгий и ограниченный набор типов данных, если это интересно.
AVK>О запросах подробнее: AVK>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов? AVK>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль?
Можно полностью отказаться от "текстовый декларативный язык запросов", если есть мощный (покрывающий реляционные операции) "функциональный стиль" + сохранение выражений в функциональном стиле в читаемый текст и восстановление из него. Разница в том, что текс получается вторичным и будет использоваться в самых крайних случаях => удобство и читабельность не очень важны.
AVK>2) Что лучше — выборки или навигационный способ(курсоры).
Выборки. Без курсоров в АДО.НЕТ можно ж обходиться.
AVK>О метаданных: AVK>1) Допустим ли отказ от специфичных для БД метаданных в пользу метаданных, встроенных в платформу?
Да.
AVK>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД?
Да.
AVK>3) Должны ли типы хранится в БД вместе с данными?
Что за типы? пользовательские? От них вообще не страшно отказаться, имхо.
AVK>О деплойменте: AVK>Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек?
Какая-то дефолтная не особомудрая — да, что бы можно было не всё самому делать, а где-то изменить то, что уже есть.
AVK>Какие еще аспекты БД было бы интересно рассмотреть с точки зрения описанной задачи?
Разграничение прав
Help will always be given at Hogwarts to those who ask for it.
P.S.
О транзакциях:
1) Оптимистичные или пессимистичные?
2) Нужны ли вложенные транзакции?
3) Можно ли обойтись без транзакций вовсе или вынести их из движка БД на уровень библиотеки?
Здравствуйте, _FRED_, Вы писали:
AVK>>О первичных ключах: AVK>>1) Допустимо ли требование обязательного наличия первичного ключа? AVK>>2) Допустимо ли требование несоставного первичного ключа? AVK>>3) Допустимо ли требование первичного ключа определенного типа? AVK>>4) Допустимо ли требование первичного ключа типа GUID?
_FR>Каждое, по-отдельности, ИМХО, недопустимо, поскольку влечёт за собой перепроектирование готовой уже схемы данных или привязку создаваемой вновь к способу хранения.
Я сейчас не хочу обсуждать совместимость со старым кодом. Интересно именно проектирование from scratch.
_FR>Можно полностью отказаться от "текстовый декларативный язык запросов", если есть мощный (покрывающий реляционные операции) "функциональный стиль"
Есть.
_FR> + сохранение выражений в функциональном стиле в читаемый текст и восстановление из него.
А это зачем?
AVK>>2) Что лучше — выборки или навигационный способ(курсоры).
_FR>Выборки.
Почему?
_FR>Без курсоров в АДО.НЕТ можно ж обходиться.
Ну и что? В первых СУБД наоборот, были только курсоры и не было выборок, и тоже вроде как обходились.
AVK>>3) Должны ли типы хранится в БД вместе с данными?
_FR>Что за типы? пользовательские? От них вообще не страшно отказаться, имхо.
Типы строк, а не колонок.
AVK>>Какие еще аспекты БД было бы интересно рассмотреть с точки зрения описанной задачи?
_FR>Разграничение прав
AndrewVK wrote: >> > Ты имеешь ввиду наследство Yaffil? Это совсем не то. > C>Нет, я имею в виду FireBird Embedded > Это оно и есть. Совсем не интересно. Это обычный SQL сервер.
(Yaffil и IB — не совсем одно и тоже, ну да ладно).
Вопрос: а почему настольные БД должны отличаться от обычных БД? Конечно,
за исключением вопросов администрирования и т.п.
> C>In-proc если к базе должен иметь доступ только один процесс > C>одновременно. В противном случае — outproc. > А зачем доступ к десктопной базе нескольких процессов? Собственно > отсуствие онного есть одна из предпосылок отличий проектных решений от > классического SQL-сервера.
Например, открыть один и тот же файл из разных программ.
>> > C>Как обычно. >> > SQL? > C>SQL, Linq, > SQL и LINQ это две очень большие разницы.
И что? Еще раз говорю — нет смысла что-то новое изобретать.
> C> навигационный доступ. Не вижу причин делать что-то отличное > C>от обычных БД. > Причина простая — для SQL необходим парсер, интерпретатор и очень > сложный оптимизатор. Это, помимо объема работы, еще и лишний оверхед.
Парсер и интерпретатор — это несерьезно, в общем объеме кода это будет
совсем немного. Сверхкрутой планировщик тоже не нужен.
Я лично реализовал нечто подобное — парсер моего языка MQL (MAPI Query
Language), выглядещего примерно так:
RESTRICT(TAGEXISTS(0x1112) AND NOT FUZZY_MATCH(TAG(0x1112),?));
RESTRICT(TAGEXISTS(0x1112) AND NOT TAGVALUE(0x1112)==TAGVALUE(0x1000));
RESTRICT(NOT COMMENT(:cat) AnD NoT( NOT NOT (COMMENT(:dog)))) ;
RESTRICT(NOT COMMENT('1') AND SUBRESTRICT('Test', NOT NOT COMMENT('1')));
К нему еще написал планировщик и бэкэнд на FireBird.
Примерно 200Кб кода на С++.
>> > Нету никакого как обычно. В разных решениях по разному. > C>Имею в виду, что нет смысла изобретать что-то новое. > А что конкретно лучше всего подойдет из старого?
Небольшая удобная БД.
> C>Так я и говорю про деплоймент баз — в строке соединения просто > C>прописывается путь до файла БД. Соответственно, для деплоймента базы > C>просто нужно положить куда-нибудь файл. > Блин, еще раз. Есть некая система Х — ей нужно создать/обновить > *структуру* БД XY, ей потребной. Весь вопрос в том как это сделать.
Обычные DDL: "INSERT COLUMN INTO ..." и т.п. В сложных случаях — создать
новую базу и перезагрузить специальной программой миграции.
>> > C>А вообще, все должно быть как можно проще и легковеснее. >> > И при этом ты советуешь SQL, out of process и DDL. Нестыковочка выходит. > C>А что, SQL уже подразумевает SQL Server? > SQL подразумевает немаленькие затраты на его парсинг и интерпретацию.
Скажите это SQLite'у.
> C>SQLite имеет SQL-движок размером в несколько сотен килобайт, в FireBird > C>около мегабайта. > И что?
То что мифические затраты на SQL далеко не так уж и велики.
Кстати, если вас так волнует скорость, то можно делать вот так:
//Определяем колонки
BOOST_RTL_DEFINE_COLUMN(std::string, Name);
BOOST_RTL_DEFINE_COLUMN(bool, IsMale);
BOOST_RTL_DEFINE_COLUMN(gregorian::date, BirthDate);
//Список полей таблицыtypedef boost::mpl::vector3<Name,IsMale,BirthDate> fld_list;
//Список полей для построения индексовtypedef boost::mpl::vector3<Name,BirthDate> idx_list;
//Информация о таблице включает в себя список полей и индексовstruct People : table_info<fld_list,idx_list>{};
expr_type epxr=select((m_people),
col<0, People::Name>() == "Thor The Mighty" &&
col<0, People::IsMale>() == true &&
col<0, People::BirthDate>() < gregorian::date("1/1/1910")
;
selection(expr,table);
С помощью Boost.Shmem получаем прозрачную persistance на диск. Вчера
попробовал этот трюк — все работало пока не кончилось адресное
пространство (примерно при размере в 1.1Гб).
Здравствуйте, AndrewVK, Вы писали:
AVK>Сразу оговорюсь, если это непонятно из исходного поста — речь об однопользовательской БД. Иначе получится yet another SQL server.
ОК
M>>Варианты M>>1. Один файл но большой — M>> преимущества: простота распространения M>> недостатки: все намешано в кучу, появляються длинные Seek при чтении поиске данных что ни есть гуд. AVK>Привод головок у винта все равно один, так что много файлов от длинных сиков не спасают.
M>>2. Много файловая БД M>> а) один файл на таблицу M>> б) один файл на все данные M>> С индексами тоже самое M>> преимущества: можно оптимизировать файлы на предмет подгонки размера страницы под конкретные данные — меньше оверхеда на пустоту, M>> недостатки: Проблемы с поддержкой кучи файлов, больше используемыъ объектов ядра
AVK>Самое непонятное — что делать если какой то файл потерялся?
Антракт негодяи В случае одного файла БД он испортиться может — тогда уж кранты всему. В случае утери индекса все лечиться перестроением оного. В общем для однопользовательской БД мне кажеться это не актуально.
AVK>>>3) Описание метаданных M>>1. DDL — чтобы иметь текстовые определения БД
AVK>А зачем?
ДЛя поддержки разработки да и для автоматического развертывания на основе только текстовых файлов.
M>>2. Метаданные в формате БД храняться в самой схеме данных БД или же лежат отдельно — как вариант отдельным файлом — описателем БД. AVK>Как определять факт несоответствия?
Можно ввести пометочки в заголовке файлов БД на предмет соотвествия схемы. Но в общем да схемы мужно запихать в сам файл данных а общую схему БД строить как совокупность всех схем описанных в файлах данных — Но тут получается логически самое простое решение — иметь один файл на БД и не париться.
AVK>>>4) Способ формирования запросов M>>SQL или объектные запросы можно вообще обойтись без запросов если делать сетевую БД
AVK>А зачем SQL?
Для поддержки сторонних тулзов — а ля Генераторы отчетов и прочей братии им без SQL будет худо.... Хотя ежели нам отчеты не уперлись можем и забить а сделать только навигационный доступ.
AVK>>>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом M>>ACID поддержка транзакционности как минимум с возможностью отката в случае чего.
AVK>Зачем, если БД однопользовательская?
Свет выключают иногда AVK>>>6) Алгоримты деплоймента M>>копирование по месту
AVK>А реструктуризация?
Во про слона то я и забыл.
Значит реструктуризация без отдельных метаданных получается странной. Не разворачивать же вторую БД параллельно только для вычитки метаданных. Или разворачивать ?
AndrewVK wrote: > M>ACID поддержка транзакционности как минимум с возможностью отката в > случае чего. > Зачем, если БД однопользовательская?
Начали мы сохранять изменения — а тут кот выдернул шнур питания (у нас
настольная БД). Вот тут-то транзакционность с ACID очень даже пригодится.
AndrewVK wrote: > О транзакциях: > 1) Оптимистичные или пессимистичные?
Зависит от потребностей и возможностей.
> 2) Нужны ли вложенные транзакции?
Обычно нет.
> 3) Можно ли обойтись без транзакций вовсе или вынести их из движка БД на > уровень библиотеки?
Лучше не надо. Транзакции замечательно на уровне БД живут, и прикладные
транзакции очень удобно делать поверх транзакций в БД.
Здравствуйте, AndrewVK, Вы писали:
AVK>Вопрос как раз в согласованности. Какого уровня констрейнты должны быть?
Мммм.. В первую очередь, естественно, согласованность данных и индексов
Возможно не имеет смысл делать констрейнты типа FK, но уникальность гарантировать надо, причем жестко увязать это с наличием индекса..
Вводить наличие хитрых Check-констрейнтов, тоже пожалуй не стоит, не первой необходимости конструкция.
Поддержка транзакционности, естественно...
Здравствуйте, AndrewVK, Вы писали:
AVK>О первичных ключах: AVK>1) Допустимо ли требование обязательного наличия первичного ключа?
Первичного ключа в смысле уникальности? Да, я думаю вполне...
AVK>2) Допустимо ли требование несоставного первичного ключа?
Да.
AVK>3) Допустимо ли требование первичного ключа определенного типа?
Ну, можно, пожалуй ограничиться первыми двумя трабованиями.
С другой стороны, можно потребовать наличия индекса на любом поле по которому производится фильтрация и вообще создавать эти индексы на автомате при первом запросе, если подходящих не обнаружилось.
AVK>О расширяемости: AVK>Что должно быть расширяемо в сабже?
В каком смысле расширяемости?
AVK>О keysets: AVK>2) Достаточно ли самого простого варианта, или нужна возможность подкрузки в кейсет части данных?
С частью данных возни много, а выхлоп непонятен... Можно разрешить грузить только данные из индексов и целиком объект.
AVK>О запросах подробнее: AVK>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов?
Вот от этого хотелось бы избавиться в противном случае есть embedded SQL сервера и непонятно зачем делать что-то еще.
AVK>О метаданных: AVK>1) Допустим ли отказ от специфичных для БД метаданных в пользу метаданных, встроенных в платформу?
Допустим, собственно с этим и было бы интересно поиграться.
AVK>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД?
Теоретически да, опять-таки интересно было бы посмотреть.
AVK>3) Должны ли типы хранится в БД вместе с данными?
Да.
AVK>О деплойменте: AVK>Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек?
В идеале да. Иначе очень большие проблемы при разработке.
AVK>Какие еще аспекты БД было бы интересно рассмотреть с точки зрения описанной задачи?
Где вести логгирование, как обеспечивать отказоустойчивость...
Сложный вопрос с большим предисловием.
Примем на время тот факт, что используем курсоры и функциональный стиль запросов. Примерный внешний вид интерфейса будет таким:
1) Объект, представляющий БД:
namespace Rsdn.JanaDB
{
/// <summary>
/// База данных.
/// </summary>public class JanaDatabase
{
private readonly string _filePath;
/// <summary>
/// Инициализирует экземпляр.
/// </summary>public JanaDatabase(string filePath)
{
_filePath = filePath;
throw new NotImplementedException();
}
/// <summary>
/// Возвращает таблицу, соответствующую переданному типу.
/// </summary>public Cursor<T> From<T>() where T : IKeyedObject
{...}
}
}
Метод From возвращает курсор на всю БД.
IKeyedObject, указанный у ограничении, просто говорит о том что у типа таблицы есть первичный ключ:
using System;
using System.Collections.Generic;
namespace Rsdn.JanaDB
{
/// <summary>
/// Содержит результат выборки.
/// </summary>public class Cursor<T>
{
/// <summary>
/// Выполняет операцию проекции.
/// </summary>
/// <typeparam name="D">тип результата</typeparam>
/// <param name="projection">операция проекции</param>public Cursor<D> Select<D>(Projection<T, D> projection)
{...}
/// <summary>
/// Выполняет операцию фильтрации.
/// </summary>public Cursor<T> Where(Filter<T> filter)
{...}
/// <summary>
/// Выполняет сортировку.
/// </summary>public Cursor<T> OrderBy<K>(KeySelector<K, T> keySelector)
{...}
/// <summary>
/// Выполняет группировку.
/// </summary>public IEnumerable<Grouping<K, T>> GroupBy<K>(KeySelector<K, T> keySelector)
{...}
}
}
Описания делегатов приводить не буду, думаю и так все понятно.
В контексте данного вопроса интересуют методы where и orderby. Что они делают, надеюсь, понятно. Вопрос в том как.
Пример запроса:
public class TestClass : KeyedObjectBase
{
private string _name;
private string _description;
public TestClass(Guid primaryKey) : base(primaryKey)
{
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Description
{
get { return _description; }
set { _description = value; }
}
}
public class NameTuple
{
private string _name;
public NameTuple(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}
...
JanaDatabase db = new JanaDatabase("");
db
.From<TestClass>()
.Where(delegate(TestClass src)
{ return src.Name != ""; })
.OrderBy<string>(delegate(TestClass src)
{ return src.Name;})
.Select<NameTuple>(delegate(TestClass src)
{ return new NameTuple(src.Name); });
Конкретизирую вопрос: если у нас нет индексов все замечательно — реализация упомянутых методов будет тривиальна. А вот если они есть, то возникает вопрос как и на каком основании их использовать. Навскидку вижу два варианта:
1) Анализ кода лямбды на предмет обнаружения понимаемых условий. В частности в примере несложно понять как использовать индекс по Name
2) Введение двух форм методов — один с лямбдой, другой с параметрами, описывающими работу с индексом.
Первый вариант удобнее для использования, но сложнее в реализации и чреват непредсказуемыми эффектами, второй значительно стабильнее, но запутывает код и усложняет добавление индексов для оптимизации. Какой вариант предпочтительнее? Или может существует третий вариант?
Здравствуйте, Cyberax, Вы писали:
>> Это оно и есть. Совсем не интересно. Это обычный SQL сервер. C>(Yaffil и IB — не совсем одно и тоже, ну да ладно).
поясню — в оригинальном FB не было embedded версии, зато она была в дятле. После слияния дятла и FB мы и получили современную FBEmbed.
C>Вопрос: а почему настольные БД должны отличаться от обычных БД?
Я уже ответил на него. Слишком многов них для настольных БД ненужного, неудобного.
C> Конечно, за исключением вопросов администрирования и т.п.
А зачем их исключать. Особенно если раскрыть т.п. поподробнее?
>> А зачем доступ к десктопной базе нескольких процессов? Собственно >> отсуствие онного есть одна из предпосылок отличий проектных решений от >> классического SQL-сервера. C>Например, открыть один и тот же файл из разных программ.
Зачем однопользовательской БД открывать файл из разных программ?
>> SQL и LINQ это две очень большие разницы. C>И что? Еще раз говорю — нет смысла что-то новое изобретать.
А я и не говорю про изобретение нового.
>> сложный оптимизатор. Это, помимо объема работы, еще и лишний оверхед. C>Парсер и интерпретатор — это несерьезно, в общем объеме кода это будет C>совсем немного. Сверхкрутой планировщик тоже не нужен.
Это серьезно, потому что там вылазит целый ряд проблем и ограничений. В частности я уже не могу использовать в запросе compile-time технологии.
C>К нему еще написал планировщик и бэкэнд на FireBird.
Здорово. Осталось выяснить зачем это все нужно однопользовательской БД.
>> А что конкретно лучше всего подойдет из старого? C>Небольшая удобная БД.
Это не ответ. Что касаемо FBEmbed, то это неудобная для десктопных задач БД.
>> Блин, еще раз. Есть некая система Х — ей нужно создать/обновить >> *структуру* БД XY, ей потребной. Весь вопрос в том как это сделать. C>Обычные DDL: "INSERT COLUMN INTO ..." и т.п. В сложных случаях — создать C> новую базу и перезагрузить специальной программой миграции.
Практика показывает что:
1) DDL не содержит команд получения информации о метаданных
2) DDL для реструктуризации весьма неудобна
3) В DDL нет никакой поддержки типизации и версионности, а также автоматического контроля структуры БД и структуры данных программы.
>> C>SQLite имеет SQL-движок размером в несколько сотен килобайт, в FireBird >> C>около мегабайта. >> И что? C>То что мифические затраты на SQL далеко не так уж и велики.
Да да. То то я гляжу, что древний и убогий JET в янусе работает быстрее новомодного MSSQL 2005.
C>Кстати, если вас так волнует скорость, то можно делать вот так: C>
//Определяем колонки
C>BOOST_RTL_DEFINE_COLUMN(std::string, Name);
C>BOOST_RTL_DEFINE_COLUMN(bool, IsMale);
C>BOOST_RTL_DEFINE_COLUMN(gregorian::date, BirthDate);
C>//Список полей таблицы
C>typedef boost::mpl::vector3<Name,IsMale,BirthDate> fld_list;
C>//Список полей для построения индексов
C>typedef boost::mpl::vector3<Name,BirthDate> idx_list;
C>//Информация о таблице включает в себя список полей и индексов
C>struct People : table_info<fld_list,idx_list>{};
C>expr_type epxr=select((m_people),
C> col<0, People::Name>() == "Thor The Mighty" &&
C> col<0, People::IsMale>() == true &&
C> col<0, People::BirthDate>() < gregorian::date("1/1/1910")
C> ;
C>selection(expr,table);
C>
Здравствуйте, Merle, Вы писали:
M>Вводить наличие хитрых Check-констрейнтов, тоже пожалуй не стоит, не первой необходимости конструкция.
Лучше их втаскивать из прикладной программы. Почему, кстати, текстовый язык запросов мне не кажется оптимальной идеей.
M>Поддержка транзакционности, естественно...
Здравствуйте, migel, Вы писали:
AVK>>>>3) Описание метаданных M>>>1. DDL — чтобы иметь текстовые определения БД
AVK>>А зачем? M>ДЛя поддержки разработки да и для автоматического развертывания на основе только текстовых файлов.
А зачем?
AVK>>Как определять факт несоответствия? M>Можно ввести пометочки в заголовке файлов БД на предмет соотвествия схемы. Но в общем да схемы мужно запихать в сам файл данных а общую схему БД строить как совокупность всех схем описанных в файлах данных — Но тут получается логически самое простое решение — иметь один файл на БД и не париться.
А теперь как это совместить с только типизированным доступом?
AVK>>А зачем SQL? M>Для поддержки сторонних тулзов — а ля Генераторы отчетов и прочей братии им без SQL будет худо.... Хотя ежели нам отчеты не уперлись можем и забить а сделать только навигационный доступ.
Понятно, опять совместимость со старым кодом.
AVK>>>>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом M>>>ACID поддержка транзакционности как минимум с возможностью отката в случае чего.
AVK>>Зачем, если БД однопользовательская? M>Свет выключают иногда
А если транзакции пессимистичные?
M>Значит реструктуризация без отдельных метаданных получается странной. Не разворачивать же вторую БД параллельно только для вычитки метаданных. Или разворачивать ?
А как тебе такой вариант:
1) БД содержит метаданные, которые актуальны для тех данных, которые она содержит.
2) В программе своя версия метаданных.
3) При попытке использовать более свежую версию метаданных БД выполняет реструктуризацию (в процессе которой в том числе обновляет метаданные и у себя унутре).
Не совсем по тому списку вопросов, который ты привел... Из собственного опыта разработки и использования собственной же системы хранения (я называю ее восстановочной БД). Может пригодятся.
О ключах, индексах и прочем. Если индексов нет, то для некоторых задач это может быть поначалу некритично. Например, при старте загружается все содержимое БД, затем все содержимое перезаписывается. Но идентификация объектов в БД все равно какая-то нужна, если потребуется производить операции над отдельными объектами. Бывает удобно, если этот OID генерирует сама БД. Причем еще удобнее, если этот OID не повторяется затем удалении/создании объектов. По моему, для OID самое важное -- знать его размер (чтобы он не плавал в диапазоне от нескольких байт до килобайт в зависимости от времени суток ). Так что GUID в качестве OID вполне допустим, имхо.
Но, даже если по началу кажется, что для задачи не нужно информацию индексировать, то затем обязательно оказывается, что информацию в БД нужно упорядочивать. Причем обычно по некольким критериям, т.е. по нескольким разным индексам. Так что, если БД будет подерживать индексы сама, не заставляя пользователя делать это самостоятельно, то это удобно. Будут ли эти индексы храниться на диске или перестраиваться в ОП при каждом открытии БД -- не столь важно. Хотя, апетиты у пользователей растут и если в БД будет со временем несколько сотен тысяч объектов или даже миллионы, то вариант с ОП будет не самым лучшим.
Что касается запросов, то, мне в большинстве случаев хватало несколько индексов по разным критериям с выполнением простейших операций -- найти по ключу, найти нижнюю/верхнюю границу диапазона. Если появляется необходимость в каких-то запросах (а-ля SQL), то... Лично я бы задумался о том, чтобы взять БД посерьезнее Но если уж делать какой-то язык запросов, то в духе SQL (например, сильно упрощенный/урезанный SQL), т.к. порог вхождения меньше. А у приложения появляется шанс в дальнейшем безболезненно переползти на настоящую РСУБД.
Что касается метаданных (например, описания схемы данных), то оно имеет смысл, если БД будет поддерживать автоматическую миграцию данных при смене схемы. Если такая миграция делается вручную, то особой пользы от метаданных нет. Если же метаданные используются, то желательно иметь контроль за соответствием схемы данных в БД и в программе. Для релационных данных это не столь серьезный вопрос, но если БД позволит хранить объектную информацию, то такой контроль серьезно помогает.
А автоматическая миграция данных при смене схемы -- это удобно. Я бы предпочел иметь эту возможность в БД.
О деплойменте. На этапе разработки хотелось бы просто подключить к себе какую-нибудь либу (несколько) и все. На этапе использования -- иметь возможность создавать и удалять БД на лету. А так же проверять существование БД. У меня обычно сценарий такой: приложение стартует, узнает из конфига, где должна быть восстановочная база, проверяет ее существование. Если базы нет, то создает новую и работает без участия пользователя.
Еще важный момент. БД должна иметь возможности самовосстановления после сбоя. Желательно корректного Опционально, перед восстановлением хорошо было бы сохранять поврежденные файлы отдельно. Чтобы, если восстановление завершиться неудачно, их можно было отослать разработчику БД с требованием исправить баги и восстановить-таки данные.
Так же важно, чтобы БД была самодефрагментируемой. Чтобы при работе с ней она не разросталась до невероятных размеров, если в ней в отдельный момент времени хранится не много объектов. Не скажу, что мне хотелось бы, чтобы БД при удалении объектов ужималась в размерах, но вот чтобы эффективно использовала уже освободившиеся места -- это важно.
Вроде основные моменты перечислил. Надеюсь, помог.
А тебе зачем?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
AndrewVK wrote: > C>Вопрос: а почему настольные БД должны отличаться от обычных БД? > Я уже ответил на него. Слишком многов них для настольных БД ненужного, > неудобного.
А я вот так не считаю.
> C> Конечно, за исключением вопросов администрирования и т.п. > А зачем их исключать. Особенно если раскрыть т.п. поподробнее?
Я имею в виду, что обычные методы и инструменты администрирования БД не
нужны для настольных. То есть бэкапы логов транзакций, например, обычно
не нужны (как и сами логи).
> C>Например, открыть один и тот же файл из разных программ. > Зачем однопользовательской БД открывать файл из разных программ?
У меня в одном проекте файл БД — это документ, который открывается
программой.
> C>Парсер и интерпретатор — это несерьезно, в общем объеме кода это будет > C>совсем немного. Сверхкрутой планировщик тоже не нужен. > Это серьезно, потому что там вылазит целый ряд проблем и ограничений. В > частности я уже не могу использовать в запросе compile-time технологии.
Тогда вам точно Boost.RTL поможет — он в compile-time строит план
запроса с помощью expression templates
> C>К нему еще написал планировщик и бэкэнд на FireBird. > Здорово. Осталось выяснить зачем это все нужно однопользовательской БД.
По очень простой причине — так как нужна БД. Например, вы не
задумывались как Outlook сортирует письма, строит дерево тредов или
делает поиск в ящиках с сотнями тысяч писем?
>> > А что конкретно лучше всего подойдет из старого? > C>Небольшая удобная БД. > Это не ответ. Что касаемо FBEmbed, то это неудобная для десктопных задач БД.
Мой опыт показывает обратное.
> C>Обычные DDL: "INSERT COLUMN INTO ..." и т.п. В сложных случаях — создать > C> новую базу и перезагрузить специальной программой миграции. > Практика показывает что: > 1) DDL не содержит команд получения информации о метаданных
Ну DDL+получение метаданных.
> 2) DDL для реструктуризации весьма неудобна > 3) В DDL нет никакой поддержки типизации и версионности, а также > автоматического контроля структуры БД и структуры данных программы.
Ну вот, сначала вы говорите про легковесность, а потом жалуетесь на
отсутствие версионности.
> C>То что мифические затраты на SQL далеко не так уж и велики. > Да да. То то я гляжу, что древний и убогий JET в янусе работает быстрее > новомодного MSSQL 2005.
Может забудем про JET вообще как про ошибку истории?
> Ужасно.
Зато оооооочень быстро
Здравствуйте, AndrewVK, Вы писали:
_FR>>… ИМХО, недопустимо, поскольку влечёт за собой перепроектирование готовой уже схемы данных или привязку создаваемой вновь к способу хранения. AVK>Я сейчас не хочу обсуждать совместимость со старым кодом. Интересно именно проектирование from scratch.
Пускай, всё равно, получается очень ограниченно. Например, исключает возможность естественных ключей… Хотя и они зачастую не пользуются популярностью… В ощем, не вижу, где не хвантило бы Guid PrimaryKey. Только то, что схема не получается универсальной
_FR>> + сохранение выражений в функциональном стиле в читаемый текст и восстановление из него. AVK>А это зачем?
Что бы запросы можно было сохранить, например, в файле конфигурации… Но там же можно хранить указание сборки\класса\метода. Согласен, отметаем.
AVK>>>2) Что лучше — выборки или навигационный способ(курсоры). _FR>>Выборки. AVK>Почему? _FR>>Без курсоров в АДО.НЕТ можно ж обходиться. AVK>Ну и что? В первых СУБД наоборот, были только курсоры и не было выборок, и тоже вроде как обходились.
Курсоры дадут возможность узнать количество записей сразу? Смысл серверных курсов какой в настольной БД? Если уж база "настольная", то пускай будет наиболее простой — попросил->получил набор. Не вижу преимущества курсора. Или просто не знаю
AVK>>>3) Должны ли типы хранится в БД вместе с данными? _FR>>Что за типы? пользовательские? От них вообще не страшно отказаться, имхо. AVK>Типы строк, а не колонок.
Тогда не понимаю
AVK>>>Какие еще аспекты БД было бы интересно рассмотреть с точки зрения описанной задачи? _FR>>Разграничение прав AVK>Для настольной однопользовательской БД???
Правильно! Отключить
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, AndrewVK, Вы писали:
AVK>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов.
Все равно получается вопрос неконкретный. Зависит от того, является ли база данных самостоятельной для desktop приложения, или же использоваться как кэш для smart client или datacenter. Это те применения которые сразу приходят в голову. AVK>Более конкретный список вопросов: AVK>1) in process или out of process?
in process. Существует возможность у каждого приложения держать свою БД независимо. AVK>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc
Файл один. Это был и остался лучший способ, поскольку существуют оптимизации по месту хранения(типа пытаемся читать как можно последовательней). AVK>3) Описание метаданных
Должно поддерживать нахождение идентификацию объекта. AVK>4) Способ формирования запросов
Декларативный, навигационный. В принципе LINQ или XQuery декларативщина + Lazy Loading навигационный. В локальной базе данных Lazy Loading не является зазорным, и слишком дорогим. AVK>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
Только контроль данных на БД. Остальное прикладное, или на основе поставляемых библиотек. AVK>6) Алгоримты деплоймента
Должна поддерживаться версионефикация.
Merle wrote: > C>Начали мы сохранять изменения — а тут кот выдернул шнур питания (у нас > C>настольная БД). Вот тут-то транзакционность с ACID очень даже пригодится. > Тут не ACID, тут A. И, в отличии от больших БД, здесь можно ограничиться > только Redo Only логом. > I здесь не нужно, в силу того, что БД однопользовательская, D здесь тоже > обеспечит аккуртная реализация логгирования, C — это отдельная тема для > обсуждения, не думаю что весь набор больших БД здесь сильно необходим...
Как вывод — не нужна только буква "I" ("A" нужна, "C" нужна частично,
"D" нужна по определению). В общем-то, согласен, хотя лично мне это было
очень полезно.
Например, я открываю письмо на редактирование — запускается транзакция.
При редактировании данные в этой транзакции изменяются, но я могу
переключиться на старое сообщение и посмотреть его исходный вариант.
Транзакции. Must have. Однозначно. Если еще и вложенные, то вообще замечательно.
Доступ к БД из разных приложений одновременно. Хотелось бы иметь, таки. Хотя бы в режиме: один может и читать и писать, а остальные хотя бы читать. Объясню почему: иногда какая-то программа крутиться постоянно, остановить ее нет возможности. Но вот глянуть, чтоже у него внутри базы твориться бывает необходимо. Обычно это связано с сохранением в БД ошибочных данных или с ошибочной обработкой корректных данных. Если есть возможность проверить данные в базе, не останавливая приложение, которое работает как-то странно, это очень удобно.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
AndrewVK wrote: > Если не достаточно тех рамок, что я описал, то пусть, для примера, это > будет почтовый клиент.
Замечательно, я как раз писал backend для Outlook'а
>> > 3) Можно ли обойтись без транзакций вовсе или вынести их из движка БД на >> > уровень библиотеки? > C>Лучше не надо. Транзакции замечательно на уровне БД живут, > Не так уж и замечательно.
В той же FB — вполне нормально.
> C> и прикладные транзакции очень удобно делать поверх транзакций в БД. > А зачем нам две механики транзакций, если можно обойтись одной?
Я имею в виду, что транзакции в приложении являются "обертками" для
транзакций в БД.
Здравствуйте, Merle, Вы писали:
AVK>>О первичных ключах: AVK>>1) Допустимо ли требование обязательного наличия первичного ключа? M>Первичного ключа в смысле уникальности? Да, я думаю вполне...
И в смысле упрожения механики FK.
M>С другой стороны, можно потребовать наличия индекса на любом поле по которому производится фильтрация и вообще создавать эти индексы на автомате при первом запросе, если подходящих не обнаружилось.
А бенефиты от этого какие?
AVK>>Что должно быть расширяемо в сабже? M>В каком смысле расширяемости?
В любом. Что может потребоваться прикладному программисту поменять на уровне операций движка с данными?
AVK>>2) Достаточно ли самого простого варианта, или нужна возможность подкрузки в кейсет части данных? M>С частью данных возни много, а выхлоп непонятен...
Выхлоп тот же, что и в случае index includes юкона.
AVK>>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД? M>Теоретически да, опять-таки интересно было бы посмотреть.
Ну если осаваться в рамках реляционной модели, то проблем вроде бы неразрешимых нет.
Здравствуйте, eao197, Вы писали:
E>Не совсем по тому списку вопросов, который ты привел...
no problem
E>О ключах, индексах и прочем. Если индексов нет, то для некоторых задач это может быть поначалу некритично. Например, при старте загружается все содержимое БД, затем все содержимое перезаписывается.
Нереально. Слишком большие ограничения.
E>Но, даже если по началу кажется, что для задачи не нужно информацию индексировать, то затем обязательно оказывается, что информацию в БД нужно упорядочивать. Причем обычно по некольким критериям, т.е. по нескольким разным индексам. Так что, если БД будет подерживать индексы сама, не заставляя пользователя делать это самостоятельно, то это удобно.
Что значит поддерживать сама?
E> А у приложения появляется шанс в дальнейшем безболезненно переползти на настоящую РСУБД.
Не интересно. Требование совместимости (даже частичной) резко отсекает огромный пласт возможных решений. Настолько огромный, что в итоге вряд ли получится что то, заметно отличающееся от современных СУБД.
E>Что касается метаданных (например, описания схемы данных), то оно имеет смысл, если БД будет поддерживать автоматическую миграцию данных при смене схемы.
Метаданные в любом случае имеют смысл, иначе непонятно от чего будет плясать сам движек.
E> Если такая миграция делается вручную, то особой пользы от метаданных нет. Если же метаданные используются, то желательно иметь контроль за соответствием схемы данных в БД и в программе. Для релационных данных это не столь серьезный вопрос, но если БД позволит хранить объектную информацию, то такой контроль серьезно помогает.
Тут все очень мутно. Для начала попробуй ответить на вопрос: в какой момент БД становится нереляционной?
E>О деплойменте. На этапе разработки хотелось бы просто подключить к себе какую-нибудь либу (несколько) и все. На этапе использования -- иметь возможность создавать и удалять БД на лету. А так же проверять существование БД.
О, именно о том как это сделать я и спрашивал.
E>Вроде основные моменты перечислил. Надеюсь, помог.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, migel, Вы писали:
AVK>>>>>3) Описание метаданных M>>>>1. DDL — чтобы иметь текстовые определения БД
AVK>>>А зачем? M>>ДЛя поддержки разработки да и для автоматического развертывания на основе только текстовых файлов. AVK>А зачем?
Ежели напирать на объектность то тогда не зачем.
AVK>>>Как определять факт несоответствия? M>>Можно ввести пометочки в заголовке файлов БД на предмет соотвествия схемы. Но в общем да схемы мужно запихать в сам файл данных а общую схему БД строить как совокупность всех схем описанных в файлах данных — Но тут получается логически самое простое решение — иметь один файл на БД и не париться.
AVK>А теперь как это совместить с только типизированным доступом?
ЭЭЭЭ а давай в БД сразу сборки с объектами положим и будет тогда вообще все автоматично а проверки версионности просто можно свести к проверке MSIL
AVK>>>А зачем SQL? M>>Для поддержки сторонних тулзов — а ля Генераторы отчетов и прочей братии им без SQL будет худо.... Хотя ежели нам отчеты не уперлись можем и забить а сделать только навигационный доступ.
AVK>Понятно, опять совместимость со старым кодом.
Если не нужно тогда в сад, просто из исходной постановки задачи сее не следовало
AVK>>>>>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом M>>>>ACID поддержка транзакционности как минимум с возможностью отката в случае чего.
AVK>>>Зачем, если БД однопользовательская? M>>Свет выключают иногда
AVK>А если транзакции пессимистичные?
А это по барабану все равно защиту на физический сброс страниц в хранилище ставить придеться.
M>>Значит реструктуризация без отдельных метаданных получается странной. Не разворачивать же вторую БД параллельно только для вычитки метаданных. Или разворачивать ?
AVK>А как тебе такой вариант: AVK>1) БД содержит метаданные, которые актуальны для тех данных, которые она содержит. AVK>2) В программе своя версия метаданных.
В каком виде? если мы договорились до того что мтаданные лежат в самой БД для проверки целостности то в каком виде эти метаданные должны лежать в модуле эту БД использующем? AVK>3) При попытке использовать более свежую версию метаданных БД выполняет реструктуризацию (в процессе которой в том числе обновляет метаданные и у себя унутре).
А не оптимальнее-ли будет сделать OrderBy на основании int Comparison<T>(T left, T right) или IComparer<T>? Тогда вложенные OrderBy отпадут и быстрота должна увеличиться.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Cyberax, Вы писали:
C>Как вывод — не нужна только буква "I" ("A" нужна, "C" нужна частично, C>"D" нужна по определению). В общем-то, согласен, хотя лично мне это было C>очень полезно.
На практике именно буква I самая заковыристая.
C>Например, я открываю письмо на редактирование — запускается транзакция. C>При редактировании данные в этой транзакции изменяются, но я могу C>переключиться на старое сообщение и посмотреть его исходный вариант.
ИМХО это уже чисто прикладная логика. Впрочем можно вынести на уровень БД, но тогда нужны вложенные транзакции или хотя бы сейвпоинты.
Здравствуйте, _FRED_, Вы писали:
_FR>Пускай, всё равно, получается очень ограниченно. Например, исключает возможность естественных ключей…
А насколько она востребованна в настольных приложениях? Чем хуже будет ввести для естественного ключа отдельный индекс?
_FR> Хотя и они зачастую не пользуются популярностью… В ощем, не вижу, где не хвантило бы Guid PrimaryKey. Только то, что схема не получается универсальной
Зато получается универсальным целый комплект другой механики, например те же FK (и более сложные виды связей).
_FR>Курсоры дадут возможность узнать количество записей сразу?
Некоторые да. Опять же — никто не мешает добежать до конца и получить выборку.
_FR> Смысл серверных курсов какой в настольной БД?
В настольной БД нет понятия серверных курсоров — они там по определению клиентские.
_FR> Если уж база "настольная", то пускай будет наиболее простой — попросил->получил набор. Не вижу преимущества курсора. Или просто не знаю
Преимущество очень простое — курсоры не нужно грузить целиком в память. Да и навигационный доступ несколько поудобнее на типеичных настольных задачах.
AVK>>>>3) Должны ли типы хранится в БД вместе с данными? _FR>>>Что за типы? пользовательские? От них вообще не страшно отказаться, имхо. AVK>>Типы строк, а не колонок.
_FR>Тогда не понимаю
AndrewVK wrote: > C>Как вывод — не нужна только буква "I" ("A" нужна, "C" нужна частично, > C>"D" нужна по определению). В общем-то, согласен, хотя лично мне это было > C>очень полезно. > На практике именно буква I самая заковыристая.
А кто говорил, что будет просто.
> C>Например, я открываю письмо на редактирование — запускается транзакция. > C>При редактировании данные в этой транзакции изменяются, но я могу > C>переключиться на старое сообщение и посмотреть его исходный вариант. > ИМХО это уже чисто прикладная логика. Впрочем можно вынести на уровень > БД, но тогда нужны вложенные транзакции или хотя бы сейвпоинты.
Зачем? Достаточно обычных одноуровневых транзакций, но с изоляцией.
AndrewVK wrote: > C>Я имею в виду, что транзакции в приложении являются "обертками" для > C>транзакций в БД. > Так и я о том же. Зачем лишний слой оберток?
Ладно. Возьмем мой пример с письмом — благодаря транзакциям в БД
прикладной код будет очень простым.
В псевдокоде:
Transaction *trans=db->begin_transaction();
Letter *letter=Letter::load_letter(id, trans);
ShowEditWindow(letter);
if (!trans->commit())
MessageBox("Транзакция провалилась").
Здравствуйте, AndrewVK, Вы писали:
AVK>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов?
IMHO вот тут как раз очень бы пригодился XML с прозрачной схемой, пригодной для рекурсивных подзапросов. Затраты на парсинг окупаются богатством тулз для конверсии и преобразования запросов. Появляется возможность автоматизированной динамической генерации запросов без синтаксического анализа кода. Например, для реализации row-level security достаточно добавить один или несколько узлов <and/> в элемент /select/where.
Далее, при необходимости миграции на более "взрослую" СУБД достаточно написать слой для XSLT-трансляции таких запросов в SQL для конкретной БД.
Но и DLinq бы тоже не помешал как более легкий уровень
AVK>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль?
А нужна ли здесь функциональщина?
Здравствуйте, AndrewVK, Вы писали:
AVK>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов.
Это что-то типа: db4o?
AVK> Более конкретный список вопросов: AVK>1) in process или out of process?
in process — зачем нам лишний оверхед
AVK>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc
У меня пока 50 на 50 "один файл" против "много файлов"
AVK>3) Описание метаданных
Схема в которой описывается структура по которой можно построить или изменить существующую схему базы. Держать отдельно, скармливать API движка который будет производить все манипуляции. Возможно предусмотреть какую то версионность для схемы.
AVK>4) Способ формирования запросов
Думаю что то linq подобное будет в самый раз.
AVK>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
API для бекапа, восстановления, возможно сжатие/оптимизации базы.
AVK>6) Алгоримты деплоймента
xcopy с приложением
Здравствуйте, AndrewVK, Вы писали:
E>>Но, даже если по началу кажется, что для задачи не нужно информацию индексировать, то затем обязательно оказывается, что информацию в БД нужно упорядочивать. Причем обычно по некольким критериям, т.е. по нескольким разным индексам. Так что, если БД будет подерживать индексы сама, не заставляя пользователя делать это самостоятельно, то это удобно.
AVK>Что значит поддерживать сама?
Ну вот у меня есть понятие slice (раздела) и возможность итерирования по элементам slice. Но индексирования объектов в slice на уровне БД нет. Когда требуется индексирование программист должен объявить в программе объект slice_image (своеобразный proxy для доступа к содержимому slice), а для каждого индекса -- объект slice_index. Каждый slice_index связывается со своим критерием сортировки и с исходным slice_image. Далее пользователь работает со slice_index-ами. Удаление объекта через какой-нибудь slice_index автоматически приводит к удалению объекта из БД, из slice_image и всех остальных slice_index. Соответственно, при добавлении объекта в slice_image, объект добавляется в БД и в каждый из slice_index-ов.
Самое большое неудобство в том, что все эти slice_image и slice_index-ы нужно делать в программе вручную. Было бы более удобно, если бы я мог просто сказать БД: дай мне объект с таким-то ключем из такого-то индекса (без всяких slice_image и slice_index). Ну или чтобы все slice_image и slice_index-ы создавались автоматом при открытии БД.
E>>Что касается метаданных (например, описания схемы данных), то оно имеет смысл, если БД будет поддерживать автоматическую миграцию данных при смене схемы.
AVK>Метаданные в любом случае имеют смысл, иначе непонятно от чего будет плясать сам движек.
Метаданные нужны, но есть разница между метаданными в программе (которые программа сама может формировать, используюя возможности рефлексии или метапрограммирования) и метаданными на диске рядом с БД.
E>> Если такая миграция делается вручную, то особой пользы от метаданных нет. Если же метаданные используются, то желательно иметь контроль за соответствием схемы данных в БД и в программе. Для релационных данных это не столь серьезный вопрос, но если БД позволит хранить объектную информацию, то такой контроль серьезно помогает.
AVK>Тут все очень мутно. Для начала попробуй ответить на вопрос: в какой момент БД становится нереляционной?
Как только мы позволяем иметь внутри объекта атрибут, который сам является объектом. Еще хуже, если этот атрибут является агрегатом объектов. Например:
Вот если БД позволяет сохранять и извлекать объекты archive_t за одну операцию, то БД уже будет нереляционной.
E>>О деплойменте. На этапе разработки хотелось бы просто подключить к себе какую-нибудь либу (несколько) и все. На этапе использования -- иметь возможность создавать и удалять БД на лету. А так же проверять существование БД.
AVK>О, именно о том как это сделать я и спрашивал.
Так а чего сложного?
Если БД хранится в одном файле -- то проверяешь его наличие. Затем пытаешься открыть БД и проверить ее целостность. Если все нормально -- БД есть.
Если БД состоит из нескольких файлов -- это это чуть более сложный случай предыдущего варианта.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
AVK>На каком уровне?
На уровне атомарности нескольких операций, ну и гарантии того, что если данные до диска доехали, то они там и останутся...
И отката в случае нарушения констрейнта, само-собой..
Здравствуйте, AndrewVK, Вы писали:
AVK>А если транзакции пессимистические
Это и есть Redo Only лог.. Если я правильно понял что ты имеешь ввиду под пессимистическими транзакциями....
AVK>, то лог вобще можно на диск не скидывать.
Кажется в этом случае есть опастность, что если что-то навернется именно во время записи, то восставновиться уже не получится, хотя есть схема No Redo/No Undo, которая примерно так и работает...
Здравствуйте, AndrewVK, Вы писали:
AVK>Разница в необходимости скидывать на диск лог.
Мммм.. не вижу связи, это целиком от подсистемы логгирования зависит... Можно действительно все в памяти сделать, а можно развесистую систему с автоматичесткой очисткой по чек-поинту или по коммиту организовать...
AVK> Ладно, перефразирую вопрос — имеет ли смысл делать транзакции подстраиваемыми под конкретную задачу или жестко вшивать их в движек БД?
Лучше жестко вшить, меньше возни с каждой конкретной задачей. В отсутствии конкурентного доступа основная задача транзакций — это обеспечить грамотный откат и устойчивость, а в этом вполне можно положиться на универсальный движек...
Здравствуйте, AndrewVK, Вы писали:
E>>Доступ к БД из разных приложений одновременно. Хотелось бы иметь, таки.
AVK>Это зацепит за собой целый грузовик проблем (особенно меня пугает необходимость параллельных транзакций) и в результате мы придем к теперешним SQL-серверам.
А можно сделать совсем просто: одна транзакция на БД в один момент времени. Кто начал -- тот работает. Остальные ждут своей очереди. Не устраивает -- вперед к SQL-серверам.
AVK>Но! Возникает вопрос межпроцессной коммуникации, сериализации, протоколов обмена, а обеспечение типизированного доступа усложняется.
Ну дык!
E>> Объясню почему: иногда какая-то программа крутиться постоянно, остановить ее нет возможности. Но вот глянуть, чтоже у него внутри базы твориться бывает необходимо. Обычно это связано с сохранением в БД ошибочных данных или с ошибочной обработкой корректных данных.
AVK>Но в десктопных приложениях очень часто используется кеш в памяти (прикладной!). Если ты напрямую влезешь в БД, то автоматом пролетишь мимо него. Тебе не кажется, что подобные запросы должны проходить все равно через прикладной слой?
Я не очень понимаю, что ты подразумеваешь под прикладным слоем...
В моем случае мне нужно был достать то, что лежит в БД. Т.к. по этой информации я мог воспроизвести ее обработку в имитаторе. Что же может потребоваться в общем случае -- не могу даже предполагать
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
AVK>О первичных ключах: AVK>1) Допустимо ли требование обязательного наличия первичного ключа? AVK>2) Допустимо ли требование несоставного первичного ключа? AVK>3) Допустимо ли требование первичного ключа определенного типа?
Лучше сразу спросить, нужен ли синтетический ключ. IMHO нужен, для однозначной идентификации объекта в памяти и его состояния на диске.
AVK>4) Допустимо ли требование первичного ключа типа GUID?
Зависит от типа задачи. Я, например, люблю GUID.
AVK>О расширяемости: AVK>Что должно быть расширяемо в сабже?
Есть ли у тебя наследование?
AVK>О keysets: AVK>1) Допустимо ли встраивание этой механики в движек БД.
Только так. AVK>2) Достаточно ли самого простого варианта, или нужна возможность подкрузки в кейсет части данных?
По условиям. AVK>3) Нужна ли многостадийная загрузка или подгрузка в 2 стадии — кейсет и остальные данные? Или может еще какой вариант?
Ключ может быть синтетическим хешем. В этом случае это у тебя будет прямой доступ. Ну и есно декларативные запросы подгружающие графы.
AVK>О запросах подробнее: AVK>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов?
Нужен другой. Для поддержки слабоструктурированных данных. Как я уже упоминал, типа LINQ или XQuery AVK>2) Что лучше — выборки или навигационный способ(курсоры).
Все вместе. AVK>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль?
Первый легче использовать, второй легче делать.
AVK>О метаданных: AVK>1) Допустим ли отказ от специфичных для БД метаданных в пользу метаданных, встроенных в платформу?
Почему бы и нет. AVK>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД?
Зависит от объема данных. AVK>3) Должны ли типы хранится в БД вместе с данными?
Почему бы нет.
AVK>О деплойменте: AVK>Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек?
Ага. Обязательно. Многие отказы от нестандартных БД происходили именно из-за сложности версионификации.
Здравствуйте, AndrewVK, Вы писали:
M>>С другой стороны, можно потребовать наличия индекса на любом поле по которому производится фильтрация и вообще создавать эти индексы на автомате при первом запросе, если подходящих не обнаружилось. AVK>А бенефиты от этого какие?
Отсутствие необходимости создавать эти индексы явно. Гарантия того, что индексы есть, а значит не надо догадываться каким именно способом выбирать данные.
Как один из вариантов, в эом случае сам объект можно физически вообще хранить в каком угодно виде, хоть сериализовать его и пожать потом, все равно найти его можно через индекс.
AVK> Что может потребоваться прикладному программисту поменять на уровне операций движка с данными?
Упорядочить физическое хранение объектов по какому-либо из индексов для ускорения доступа, но это не первой необходимости конструкция.
Те же index include...
AVK>Выхлоп тот же, что и в случае index includes юкона.
Так и сделать это в виде того же index include, просто дать возможность включать в индекс дополнительные поля с данными и хранить их вместе с индексом.
Здравствуйте, AndrewVK, Вы писали:
AVK>На практике именно буква I самая заковыристая.
I очень заковыристая, в случае если у тебя модель данных и объектная модель не слишком совпадают. Фактически, уровень оптимистических транзакций вполне должно хватить за глаза.
C>>Например, я открываю письмо на редактирование — запускается транзакция. C>>При редактировании данные в этой транзакции изменяются, но я могу C>>переключиться на старое сообщение и посмотреть его исходный вариант.
AVK>ИМХО это уже чисто прикладная логика. Впрочем можно вынести на уровень БД, но тогда нужны вложенные транзакции или хотя бы сейвпоинты.
Зачем? Не нужны. У тебя есть состояние в памяти. А сохранять его атомарно.
AVK>>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов?
R>IMHO вот тут как раз очень бы пригодился XML с прозрачной схемой, пригодной для рекурсивных подзапросов. Затраты на парсинг окупаются богатством тулз для конверсии и преобразования запросов. Появляется возможность автоматизированной динамической генерации запросов без синтаксического анализа кода. Например, для реализации row-level security достаточно добавить один или несколько узлов <and/> в элемент /select/where.
При сложных запросах он будет нечитаем:
SQL
SELECT id, name FROM people WHERE name <> 'Mamut' AND city_id=1 ORDER BY name DESC
------
XML pseudo
<statement>
<select>
<fields>
<field name="id" table="people">
<field name="name" table="people">
</fields>
<constraints>
<notequal>
<field name="name" value="Mamut">
</notequal>
<equal>
<field name="city_id" value="1">
</equal>
</constraints>
<order>
<field name="name" value="desc">
</order>
</select>
</statement>
------
Какой-нить функциональный язык pseudo (на основе Erlang + Mnesia):
Q = query [E.name, E.id || E <- table(people), E.name != 'Mamut', E.city_id = 1]
Вот чтобы я приветствовал — это язык запросов вроде list comprehensions, но мало для каких языков это будет возможно...
Здравствуйте, AndrewVK, Вы писали:
AVK>Зато получается универсальным целый комплект другой механики, например те же FK (и более сложные виды связей).
+1 Это если это для решения задачи важнее, то несомненно плюсов от граничения: «В каждой таблице есть Guid-первичный ключ» очень много. В подобном аспекте более чем разумное требование.
_FR>> Если уж база "настольная", то пускай будет наиболее простой — попросил->получил набор. Не вижу преимущества курсора. Или просто не знаю AVK>Преимущество очень простое — курсоры не нужно грузить целиком в память. Да и навигационный доступ несколько поудобнее на типеичных настольных задачах.
А зачем они могут понадобится такие? Перебор элементов (подсчёт агрегатов) и фильтрацию можно осуществить в запросе, если язык позволяет. Зачем ещё может понадобится курсор на клиенте, кроме как для того, что бы пробежать его до конца?
AVK>>>>>3) Должны ли типы хранится в БД вместе с данными? _FR>>>>Что за типы? пользовательские? От них вообще не страшно отказаться, имхо. AVK>>>Типы строк, а не колонок. _FR>>Тогда не понимаю AVK>А что конкретно непонятно?
Как предполагается хранить описание таблиц? Что это в понятии разрабатываемой БД? Набор колонок, или описание типа-объекта строки? Видимо второе…
... << RSDN@Home 1.2.0 alpha rev. 648>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, AndrewVK, Вы писали:
AVK>>>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД AB>>Как MS-Access, только с триггерами AVK>Этой каки я уже накушался, больше не надо. И нафига настольной БД триггеры?
Триггеры для того, чтобы пользователь мог редактировать данные в режиме таблицы как из самой Access, так и чтобы вынести часть логики из приложения. Можно и без них, но иногда хочется маленького счастья — внес проплату прямо ручками и в режиме таблицы, а она автоматически раскидалась по счетам, например. А так как записей всего 100-200 тыс — это не сильно заметно.
По поводу каки. Интеграция с другими продуктами офиса, наличие драйвера в стандартном MDAC, автоматическое обновление с WindowsUpdate, наличие оболочки почти на каждой машине, выбор команды RSDN... Как там было у Джоэля? "Большинство функций-таки работают"
Здравствуйте, eao197, Вы писали:
E>А можно сделать совсем просто: одна транзакция на БД в один момент времени. Кто начал -- тот работает. Остальные ждут своей очереди. Не устраивает -- вперед к SQL-серверам.
Даже если у тебя разрешено иметь несколько инстансов, или у тебя MDI приложение?
Здравствуйте, GlebZ, Вы писали:
E>>А можно сделать совсем просто: одна транзакция на БД в один момент времени. Кто начал -- тот работает. Остальные ждут своей очереди. Не устраивает -- вперед к SQL-серверам. GZ>Даже если у тебя разрешено иметь несколько инстансов, или у тебя MDI приложение?
Несколько инстанцев -- это о чем?
MDI приложение -- это все равно одно приложение. Внутри приложения доступ к БД можно через обычные средства синхронизации делать.
И если речь зашла о поддержке параллельных транзакций, то уже не так сложно будет перейти от поддержки параллельных транзакций в рамках одного приложения к такой же поддержке в нескольких приложениях.
И кстати, у меня лично такая политика (одна транзакция в один момент времени) в многопоточных приложениях вполне себе прокатывает. Может со временем и не будет хватать, нопока хватает.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
GZ>>Даже если у тебя разрешено иметь несколько инстансов, или у тебя MDI приложение? E>Несколько инстанцев -- это о чем?
А то, что у меня пользователи требуют возможность открытие нескольких инстансов одновременно. И под разными логинами.
E>MDI приложение -- это все равно одно приложение. Внутри приложения доступ к БД можно через обычные средства синхронизации делать.
Что значит "обычные средства синхронизации".
E>И если речь зашла о поддержке параллельных транзакций, то уже не так сложно будет перейти от поддержки параллельных транзакций в рамках одного приложения к такой же поддержке в нескольких приложениях.
E>И кстати, у меня лично такая политика (одна транзакция в один момент времени) в многопоточных приложениях вполне себе прокатывает. Может со временем и не будет хватать, нопока хватает.
В случае если у тебя транзакция начинается вместе с открытием формы?
AndrewVK wrote: > 1) Анализ кода лямбды на предмет обнаружения понимаемых условий. В > частности в примере несложно понять как использовать индекс по Name > 2) Введение двух форм методов — один с лямбдой, другой с параметрами, > описывающими работу с индексом.
Кстати, вспомнил вот еще такой подход для нестандартных решений.
В одном проекте надо было сохранять большой и достаточно сложный граф
объектов. Этот граф постоянно пополнялся, но старые объекты изменялись
редко.
Делали так — в первый раз сериализовали граф целиком (обычной
сериализацией), а в дальнейшем записывали только команды изменения
(добавить объект в коллекцию/изменить поле объекта/и т.п.). При загрузке
сначала читали весь граф, а потом запускали команды изменения (мы
назвали этот процесс "reweaving"). Когда объем команд превышал
определенный предел — перезаписывали граф полностью.
Потом еще добавили несколько оптимизаций: хранили таблицу удаленных
объектов, чтобы их не десериализывать зря, использовали ленивую загрузку
и т.п.
Здравствуйте, Cyberax, Вы писали:
>> неудобного. C>А я вот так не считаю.
Ну ОК. Тогда мои вопросы не для тебя.
>> C> Конечно, за исключением вопросов администрирования и т.п. >> А зачем их исключать. Особенно если раскрыть т.п. поподробнее? C>Я имею в виду, что обычные методы и инструменты администрирования БД не C>нужны для настольных. То есть бэкапы логов транзакций, например, обычно C>не нужны (как и сами логи).
А нужна ли изоляция транзакций? Нужен ли универсальный язык запросов? Нужен ли тот или иной вид выполнения кода внутри БД? Нужны ли собственные метаданные? Нужна ли механика коммуникации? Нужен ли прикладной слой преобразования типов БД в типы среды исполнения прикладного кода?
>> Зачем однопользовательской БД открывать файл из разных программ? C>У меня в одном проекте файл БД — это документ, который открывается C>программой.
Классно. Но я ведь не про твой проект спрашиваю.
>> частности я уже не могу использовать в запросе compile-time технологии. C>Тогда вам точно Boost.RTL поможет — он в compile-time строит план C>запроса с помощью expression templates
Это уже не суть важно. Я ведь не про реализацию спрашиваю.
>> C>К нему еще написал планировщик и бэкэнд на FireBird. >> Здорово. Осталось выяснить зачем это все нужно однопользовательской БД. C>По очень простой причине — так как нужна БД.
C> Например, вы не задумывались как Outlook сортирует письма, строит дерево тредов или C>делает поиск в ящиках с сотнями тысяч писем?
И? Ты хочешь сказать что без текстового языка запросов эту задачу не решить?
>> Это не ответ. Что касаемо FBEmbed, то это неудобная для десктопных задач БД. C>Мой опыт показывает обратное.
А мой нет.
>> 1) DDL не содержит команд получения информации о метаданных C>Ну DDL+получение метаданных.
А как насчет типизированного доступа к данным?
C>Ну вот, сначала вы говорите про легковесность, а потом жалуетесь на C>отсутствие версионности.
А я говорю про легковесность? Я говорю лишь про выкидывание ненужного для десктопа функционала. Реструктуризация для него пожалуй даже нужнее чем для клиент-сервера.
>> Да да. То то я гляжу, что древний и убогий JET в янусе работает быстрее >> новомодного MSSQL 2005. C>Может забудем про JET вообще как про ошибку истории?
Здравствуйте, Anton Batenev, Вы писали:
AB>Триггеры для того, чтобы пользователь мог редактировать данные в режиме таблицы как из самой Access
Я правильно понимаю, что настольная БД должна, по твоему, редактироваться из Access?
AB>, так и чтобы вынести часть логики из приложения.
in process БД это уже часть приложения, так что никуда ты ничего не вынесешь. Если же речь о слоях абстракции, то это можно сделать и без триггеров.
AB> Можно и без них, но иногда хочется маленького счастья — внес проплату прямо ручками и в режиме таблицы, а она автоматически раскидалась по счетам, например. А так как записей всего 100-200 тыс — это не сильно заметно.
Ну и чего тут сложного? Поскольку у нас in process, то просто подвешиваемся на какое нибудь событие или делаем где нибудь в объекте виртуальный метод.
AB>По поводу каки. Интеграция с другими продуктами офиса,
Интеграцию можно производить на разных уровнях, не обязательно на уровне БД.
AB> наличие драйвера в стандартном MDAC,
В случае JET отсутствуют начиная с версии 2.6
AB> автоматическое обновление с WindowsUpdate,
Отсутствует
AB> наличие оболочки почти на каждой машине,
Для десктопа не критично.
AB> выбор команды RSDN...
Здравствуйте, migel, Вы писали:
AVK>>А зачем? M>Ежели напирать на объектность то тогда не зачем.
Не на объектность, на типизированность. Это вобщем то не одно и то же. А объектность? Ну разве что аналоги триггеров через объекты зацепить.
AVK>>А теперь как это совместить с только типизированным доступом? M>ЭЭЭЭ а давай в БД сразу сборки с объектами положим и будет тогда вообще все автоматично а проверки версионности просто можно свести к проверке MSIL
Верная мысль
AVK>>А если транзакции пессимистичные? M>А это по барабану все равно защиту на физический сброс страниц в хранилище ставить придеться.
Зачем? При пессимистичной транзакции сброс происходит когда откат уже не возможен.
M>В каком виде? если мы договорились до того что мтаданные лежат в самой БД для проверки целостности то в каком виде эти метаданные должны лежать в модуле эту БД использующем?
Здравствуйте, Merle, Вы писали:
AVK>>А если транзакции пессимистические M>Это и есть Redo Only лог.. Если я правильно понял что ты имеешь ввиду под пессимистическими транзакциями....
Я имею ввиду собственно то, что под этим обычно стандартно понимают. Оптимистичные транзакции, это когда пишем в лог, потом пишем в БД, а если откатываемся, то делаем над БД обратные операции. Пессимистичные, это когда лог и новые версии накапливаем в памяти, а при коммите вносим изменения в БД.
Здравствуйте, GlebZ, Вы писали:
E>>Несколько инстанцев -- это о чем? GZ>А то, что у меня пользователи требуют возможность открытие нескольких инстансов одновременно. И под разными логинами.
Мы сейчас про настольную (неявно подразумевается встроенная) БД говорим, или про серверную-многопользовательскую?
Если мы про встраиваемую, то под несколькими инстансами можно понимать и вот это:
// Первый инстанс.
some_cool_db_t first_db( "my_cool_db.dat" );
// А вот и второй.
some_cool_db_t second_db( "my_cool_db.dat" ); // Опаньки! :)
в такой ситуации first_db и second_db могут просто не понимать, что они лезут к одному физическому файлу.
У меня можно сделать вот так:
/* Примечание: в реальном коде все это сдабривается std::auto_ptr-ами! */
// Этот объект физически выполняет все действия над БД.
oess_1::db::site::localhost_t * localhost = oess_1::db::site::create_db_localhost();
// Этот объект должен знать, с какой физической БД мы работаем.
// Физически БД будет открыта при первом реальном обращении к ней.
localhost->db_describe(
// Этот псевдоним будет использоваться в дальнейшем. Он позволяет абстрагироваться от конкретных имен."my_database",
// Это физическое имя БД."~/my_cool_app/dat/default",
// Конфигурационный файл с описаниями параметров БД."~/my_cool_app/dat/default.cfg",
// Открываем в read-write режиме.false,
// Разрешаем автоматическое восстановление БД в случае сбоя.true );
// А вот через такой объект будет вестись прикладная работа.
oess_1::db::cln::db_t * first_db = oess_1::db::cln::create_std_db(
// Вот так устанавливается связь между объектом localhost и first_db.
oess_1::db::site::create_std_localhost_connector( *localhost ) );
// Подключаемся к БД и начинаем работать с ней.
// Именно в этот момент localhost начнет работать с файлами БД.
first_db->attach( "my_database" );
// А вот так создается второе подключение к той же БД.
oess_1::db::cln::db_t * second_db = oess_1::db::cln::create_std_db(
// Вот так устанавливается связь между объектом localhost и first_db.
oess_1::db::site::create_std_localhost_connector( *localhost ) );
second_db->attach( "my_database" );
Я думаю, что ты про такие инстансы говорил?
E>>MDI приложение -- это все равно одно приложение. Внутри приложения доступ к БД можно через обычные средства синхронизации делать. GZ>Что значит "обычные средства синхронизации".
Если брать C++, то mutex-ы и condition variables. Если Java, то synchonized-секции.
GZ>В случае если у тебя транзакция начинается вместе с открытием формы?
Да, в этом случае будут кранты. Только я с формами свою БД не использую
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, _FRED_, Вы писали:
_FR>+1 Это если это для решения задачи важнее,
Мне так кажется, что для настольной БД один из важнейших параметров это удобство использования.
_FR>А зачем они могут понадобится такие? Перебор элементов (подсчёт агрегатов) и фильтрацию можно осуществить в запросе, если язык позволяет.
В запросе нужно будет поднять все и сразу в память. Ну как бы тебе объяснить на пальцах — представляешь разницу между XmlDocument и XmlReader, или между DataSet и IDataReader? Вот первый это выборка, а второй — курсор.
_FR> Зачем ещё может понадобится курсор на клиенте, кроме как для того, что бы пробежать его до конца?
Для того чтобы пробежать до конца не нужно все данные сразу держать в памяти. Как правило в программе уже есть прикладные структуры данных (DAL). В случае выборки сначала мы формируем выборку, а затем копируем ее в объекты DAL. Курсор позволит заливать данные из БД в эти объекты сразу, без промежуточных буферов.
AVK>>>>>>3) Должны ли типы хранится в БД вместе с данными? _FR>>>>>Что за типы? пользовательские? От них вообще не страшно отказаться, имхо. AVK>>>>Типы строк, а не колонок. _FR>>>Тогда не понимаю AVK>>А что конкретно непонятно?
_FR>Как предполагается хранить описание таблиц?
Здравствуйте, Cyberax, Вы писали:
>> C>Я имею в виду, что транзакции в приложении являются "обертками" для >> C>транзакций в БД. >> Так и я о том же. Зачем лишний слой оберток? C>Ладно. Возьмем мой пример с письмом — благодаря транзакциям в БД C>прикладной код будет очень простым.
C>В псевдокоде: C>
Здравствуйте, Merle, Вы писали:
AVK>>Разница в необходимости скидывать на диск лог. M>Мммм.. не вижу связи, это целиком от подсистемы логгирования зависит... Можно действительно все в памяти сделать, а можно развесистую систему с автоматичесткой очисткой по чек-поинту или по коммиту организовать...
Не зависит. При оптимистических транзакциях мы обязаны скидывать лог на диск, иначе при сбоях мы не сможем обеспечить откат (лог потерян, а изменения внесены).
Здравствуйте, AndrewVK, Вы писали:
AVK>>>Разница в необходимости скидывать на диск лог. M>>Мммм.. не вижу связи, это целиком от подсистемы логгирования зависит... Можно действительно все в памяти сделать, а можно развесистую систему с автоматичесткой очисткой по чек-поинту или по коммиту организовать...
AVK>Не зависит. При оптимистических транзакциях мы обязаны скидывать лог на диск, иначе при сбоях мы не сможем обеспечить откат (лог потерян, а изменения внесены).
К слову о транзакциях и write ahead log-ах.
Кстати, Андрей, ты в курсе, что есть еще один механизм обеспечения транзакционности, без лога? Это когда новые значения объектов при изменении в транзакции записываются на новое место. Если в течении транзакции они обновляются, то обновляются уже на новом месте. Фиксация транзакции заключается в изменении ссылки на значение объекта (ссылка на старое расположение ссылкой на новое расположение). В таком подходе главный фокус -- это обеспечить атомарность изменения ссылок не измененные транзакцией объекты. Зато при фиксации транзакции нет надобности писать объекты дважды. И восстановление после сбоя так же тривиальное -- достаточно восстановить таблицу ссылок.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Merle, Вы писали:
AVK>>А бенефиты от этого какие? M>Отсутствие необходимости создавать эти индексы явно.
Не уверен что это допустимо. Потому как некоторые индексы могут быть очень большими по размеру. И tradeof между скоростью поиска и скоростью модификации никто не отменял.
M>Как один из вариантов, в эом случае сам объект можно физически вообще хранить в каком угодно виде, хоть сериализовать его и пожать потом, все равно найти его можно через индекс.
Построение нового индекса в таком варианте будет очень долгой операцией.
Здравствуйте, eao197, Вы писали:
E>А можно сделать совсем просто: одна транзакция на БД в один момент времени. Кто начал -- тот работает. Остальные ждут своей очереди. Не устраивает -- вперед к SQL-серверам.
Тогда другая проблема — невозможность длинных транзакций. Возьмем почтовый клиент — предположим мы в процессе редактирования сообщения начали транзакцию. В этот момент сетевой блок получил новые письма. Так вот — ему придется курить пока мы не закроем окно редактирования.
AVK>>Но! Возникает вопрос межпроцессной коммуникации, сериализации, протоколов обмена, а обеспечение типизированного доступа усложняется.
E>Ну дык!
Здравствуйте, retalik, Вы писали:
R>IMHO вот тут как раз очень бы пригодился XML с прозрачной схемой, пригодной для рекурсивных подзапросов. Затраты на парсинг окупаются богатством тулз для конверсии и преобразования запросов.
А зачем эти тулзы нужны?
R> Появляется возможность автоматизированной динамической генерации запросов без синтаксического анализа кода.
Тут вобще не понял. Зачем для генерации запросов синтаксический анализ?
R> Например, для реализации row-level security достаточно добавить один или несколько узлов <and/> в элемент /select/where.
row level security в настольной БД???
R>Далее, при необходимости миграции на более "взрослую" СУБД достаточно написать слой для XSLT-трансляции таких запросов в SQL для конкретной БД.
По поводу миграции я уже высказывался.
R>Но и DLinq бы тоже не помешал как более легкий уровень
Просто LINQ. DLINQ намертов подвязан на ADO.NET.
AVK>>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль? R>А нужна ли здесь функциональщина?
AndrewVK wrote: > Я имею ввиду собственно то, что под этим обычно стандартно понимают. > Оптимистичные транзакции, это когда пишем в лог, потом пишем в БД, а > если откатываемся, то делаем над БД обратные операции. Пессимистичные, > это когда лог и новые версии накапливаем в памяти, а при коммите вносим > изменения в БД.
Вообще-то, оптимистическими и пессимистическими бывают _блокировки_.
При оптимистической блокировке мы читаем данные из базы и запоминаем их
версию. Затем мы используем данные (в частности меняем их). При коммите
происходит блокировка БД, потом проверяется версия наших данных и тех
что в БД. При несовпадении версий — кидаем исключение. При совпадении —
инкрементируем версию в БД и разблокируем ее.
Пессимистические блокировки — просто блокируем те записи, с которыми
работаем, чтобы другие не могли их поменять.
При оптимистичных блокировках БД блокирована только на короткое время
коммита, а в пессимистичных блокировках мы вынуждены держать блокировку
все время работы с записями.
ЗЫ: в частности, MAPI требует оптимистических блокировок.
Здравствуйте, AndrewVK, Вы писали:
AVK>Не на объектность, на типизированность. Это вобщем то не одно и то же. А объектность? Ну разве что аналоги триггеров через объекты зацепить.
Намекаеш на туплесы(мултепсы ).
AVK>>>А теперь как это совместить с только типизированным доступом? M>>ЭЭЭЭ а давай в БД сразу сборки с объектами положим и будет тогда вообще все автоматично а проверки версионности просто можно свести к проверке MSIL
AVK>Верная мысль
AVK>>>А если транзакции пессимистичные? M>>А это по барабану все равно защиту на физический сброс страниц в хранилище ставить придеться.
AVK>Зачем? При пессимистичной транзакции сброс происходит когда откат уже не возможен.
Шура — это не наш метод .... Это не есть гуд для любой БД и тем более с претензией на целостность данных...
M>>В каком виде? если мы договорились до того что мтаданные лежат в самой БД для проверки целостности то в каком виде эти метаданные должны лежать в модуле эту БД использующем?
AVK>В том же самом, очевидно
Я понял что из "того же материала" только не понял из какого
или мы должны держать с собой пустую БД с метаданными или мы имеем возможность иметь метаданные без БД давай решать.
Здравствуйте, GlebZ, Вы писали:
AVK>>О первичных ключах: AVK>>1) Допустимо ли требование обязательного наличия первичного ключа? AVK>>2) Допустимо ли требование несоставного первичного ключа? AVK>>3) Допустимо ли требование первичного ключа определенного типа? GZ>Лучше сразу спросить, нужен ли синтетический ключ. IMHO нужен, для однозначной идентификации объекта в памяти и его состояния на диске.
В п.3 несколько более жесткое требование.
AVK>>4) Допустимо ли требование первичного ключа типа GUID? GZ>Зависит от типа задачи. Я, например, люблю GUID.
Тип задачи — настольная однопользовательская БД.
AVK>>О расширяемости: AVK>>Что должно быть расширяемо в сабже? GZ>Есть ли у тебя наследование?
Пока речь шла только о типизации. Про объектность это еще надо обсуждать.
GZ>Ключ может быть синтетическим хешем. В этом случае это у тебя будет прямой доступ. Ну и есно декларативные запросы подгружающие графы.
Т.е ОО-БД?
AVK>>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов? GZ>Нужен другой. Для поддержки слабоструктурированных данных.
Тебе не кажется что это выходит за рамки БД, особенно настольной?
GZ> Как я уже упоминал, типа LINQ или XQuery
lINQ это не текстовый язык запросов, это языковая конструкция.
AVK>>2) Что лучше — выборки или навигационный способ(курсоры). GZ>Все вместе.
Они взаимозаменяемы. Если есть один, то другой может быть реализован ввиде библиотеки.
AVK>>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД? GZ>Зависит от объема данных.
Ты, мне кажется, опять начинаешь путать ООБД и типизированные запросы.
Здравствуйте, Cyberax, Вы писали:
C>Делали так — в первый раз сериализовали граф целиком (обычной C>сериализацией), а в дальнейшем записывали только команды изменения C>(добавить объект в коллекцию/изменить поле объекта/и т.п.). При загрузке C>сначала читали весь граф, а потом запускали команды изменения (мы C>назвали этот процесс "reweaving"). Когда объем команд превышал C>определенный предел — перезаписывали граф полностью.
Здравствуйте, GlebZ, Вы писали:
AVK>>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов. GZ>Все равно получается вопрос неконкретный.
Лишний повод включить фантазию
GZ> Зависит от того, является ли база данных самостоятельной для desktop приложения, или же использоваться как кэш для smart client или datacenter.
А зачем для кеша какая то особенная БД?
AVK>>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc GZ>Файл один. Это был и остался лучший способ, поскольку существуют оптимизации по месту хранения(типа пытаемся читать как можно последовательней).
На физическое расположение файла на диске все равно прикладная программа не влияет.
AVK>>3) Описание метаданных GZ>Должно поддерживать нахождение идентификацию объекта.
Здравствуйте, Andre, Вы писали:
AVK>>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов.
A>Это что-то типа: db4o?
Нет.
AVK>>4) Способ формирования запросов A>Думаю что то linq подобное будет в самый раз.
У LINQ (как его тут любят поминать ) есть два варианта запросов — декларативный и функциональный. Luke Hoban говорит, что функциональный понятнее, хоть и не похож внешне на SQL.
AndrewVK wrote: > А нужна ли изоляция транзакций? Нужен ли универсальный язык запросов?
Зависит от задачи. В персональном дневнике — может и не нужно. В
хранилище почтовых сообщений — нужно с большой вероятностью.
> Нужен ли тот или иной вид выполнения кода внутри БД?
Вот это как раз скорее всего не нужно.
> Нужны ли собственные метаданные? Нужна ли механика коммуникации? Нужен ли > прикладной слой преобразования типов БД в типы среды исполнения > прикладного кода?
Зависит от желаний и потребностей.
> C>У меня в одном проекте файл БД — это документ, который открывается > C>программой. > Классно. Но я ведь не про твой проект спрашиваю.
Я просто приводил use-case, когда это может быть нужно.
> C>Тогда вам точно Boost.RTL поможет — он в compile-time строит план > C>запроса с помощью expression templates > Это уже не суть важно. Я ведь не про реализацию спрашиваю.
Стоит посмотреть даст ли compile-time планирование какие-то существенные
преимущества — может проще при старте программы скомпилировать все
SQL-запросы.
>> > C>К нему еще написал планировщик и бэкэнд на FireBird. >> > Здорово. Осталось выяснить зачем это все нужно однопользовательской БД. > C>По очень простой причине — так как нужна БД.
Уточню, база сообщений Outlook'а — это фактически целая БД с
транзакциями, языком запросов и сортировки.
> И? Ты хочешь сказать что без текстового языка запросов эту задачу не решить?
Все равно нужен механизм _настриваемых_ запросов (то есть я могу выбрать
сортировку по custom-ной колонке "ДатаДляМенеджера" и по колонке "Статус").
Чистым compile-time'ом не обойдешься, нужно делать хотя бы что-то типа
ICriteria. А написать транслятор [x]QL в дерево критерия — задача не
очень сложная.
>> > 1) DDL не содержит команд получения информации о метаданных > C>Ну DDL+получение метаданных. > А как насчет типизированного доступа к данным?
С этом сложнее.
> C>Ну вот, сначала вы говорите про легковесность, а потом жалуетесь на > C>отсутствие версионности. > А я говорю про легковесность? Я говорю лишь про выкидывание ненужного > для десктопа функционала. Реструктуризация для него пожалуй даже нужнее > чем для клиент-сервера.
Просто я не вижу лишнего в функциональность БД.
Здравствуйте, AndrewVK, Вы писали:
AVK>Тогда другая проблема — невозможность длинных транзакций. Возьмем почтовый клиент — предположим мы в процессе редактирования сообщения начали транзакцию. В этот момент сетевой блок получил новые письма. Так вот — ему придется курить пока мы не закроем окно редактирования.
Ну просто для таких вещей требования заранее озвучивать нужно
А длительные транзакции -- это весьма серьезное требование.
Кстати о длительных транзакциях. Если в ней будет изменяться всего один объект (письмо в почтовой программе), то возможен еще один подход. Транзакции кратковременные, но вот объекты можно специально помечать как временно изъятые (по-моему, в какой-то ООСУБД это дело называлось check out). Т.е., перед началом редактирования письма ты делаешь его checkout. В этот момент никто не может его изменить или удалить. Затем ты фиксируешь его новое значение и выполняешь возврат (checkin). Такие долговременные блокировки своего рода.
AVK>>>Но! Возникает вопрос межпроцессной коммуникации, сериализации, протоколов обмена, а обеспечение типизированного доступа усложняется.
E>>Ну дык!
AVK>Ну вот и получиться sql-сервер.
AFAIK, в BerkeleyDB делается так: весь кэш и все данные открытой БД размещаются в разделяемой памяти. Процессы, которые с ней работают, используют обычную синхронизацию для доступа к этой памяти. Достаточно просто и этой схеме до SQL сервера еще расти и расти.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
_FR>>А зачем они могут понадобится такие? Перебор элементов (подсчёт агрегатов) и фильтрацию можно осуществить в запросе, если язык позволяет.
AVK>В запросе нужно будет поднять все и сразу в память. Ну как бы тебе объяснить на пальцах — представляешь разницу между XmlDocument и XmlReader, или между DataSet и IDataReader? Вот первый это выборка, а второй — курсор.
Это я понимаю. Но IDataReader, например, как часто ты используешь? Для каких задач? С XmlReader — немного другое. Он один позволяет пробегать по совершенно различным сущностям — он деревообразный, по нему осуществляется доступ к объектам разных типов. К реляционной моделе, ИМХО, когда результаты выборки — объекты одной и той же структуры, такой необходимости в нём нет.
_FR>> Зачем ещё может понадобится курсор на клиенте, кроме как для того, что бы пробежать его до конца?
AVK>Для того чтобы пробежать до конца не нужно все данные сразу держать в памяти. Как правило в программе уже есть прикладные структуры данных (DAL). В случае выборки сначала мы формируем выборку, а затем копируем ее в объекты DAL. Курсор позволит заливать данные из БД в эти объекты сразу, без промежуточных буферов.
Ага, а мне показалось, что предлагается, что СУБД уже будет хранилищем объектов с логикой, (аналог ICollection<>) и спор ведётся о том, не заменить-ли ICollection<> на IEnumerable<>…
_FR>>Как предполагается хранить описание таблиц? AVK>Например ввиде .NET сборок.
Вернее, класс в сборке, помеченный, например, каким-нить аттрибутом, определяет таблицу?
... << RSDN@Home 1.2.0 alpha rev. 648>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, eao197, Вы писали:
E>Кстати, Андрей, ты в курсе, что есть еще один механизм обеспечения транзакционности, без лога? Это когда новые значения объектов при изменении в транзакции записываются на новое место.
Новые значения объектов в отдельном месте это и есть лог.
E> Если в течении транзакции они обновляются, то обновляются уже на новом месте. Фиксация транзакции заключается в изменении ссылки на значение объекта
Какого объекта? Откуда у вас все время какие то объекты вылазят? Ты имеешь ввиду создание копий страниц В+ дерева и коррекция ссылок в родительском узле и соседях? Думаю за счет сиков это будет медленнее чем просто переписать страницу поверх. И не забывай об индексах.
Здравствуйте, migel, Вы писали:
AVK>>Зачем? При пессимистичной транзакции сброс происходит когда откат уже не возможен. M>Шура — это не наш метод .... Это не есть гуд для любой БД и тем более с претензией на целостность данных...
С целостностью там все в порядке — все равно ведь сброс на диск атомарен. Там проблема с учетом изменений в той же транзакции, но при наличии кеша страниц она довольно просто решаема.
AVK>>В том же самом, очевидно M>Я понял что из "того же материала" только не понял из какого M>или мы должны держать с собой пустую БД с метаданными или мы имеем возможность иметь метаданные без БД давай решать.
Здравствуйте, AndrewVK, Вы писали:
_FR>>А не оптимальнее-ли будет сделать OrderBy на основании int Comparison<T>(T left, T right) или IComparer<T>?
AVK>Попробуй подумать. Что будет в качестве T в приведенном запросе?
Здравствуйте, AndrewVK, Вы писали:
_FR>>А не оптимальнее-ли будет сделать OrderBy на основании int Comparison<T>(T left, T right) или IComparer<T>? AVK>Попробуй подумать. Что будет в качестве T в приведенном запросе?
То, что указано во From<> и Where<>.
... << RSDN@Home 1.2.0 alpha rev. 648>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Это я понимаю. Но IDataReader, например, как часто ты используешь?
Часто. Значительно чаще чем DataSet.
_FR> Для каких задач?
Для задач работы с БД.
_FR> С XmlReader — немного другое. Он один позволяет пробегать по совершенно различным сущностям — он деревообразный,
Нет, он плоский. Потому что бежит по плоскому файлу.
_FR> по нему осуществляется доступ к объектам разных типов.
Это не играет никакой роли.
_FR>Ага, а мне показалось, что предлагается, что СУБД уже будет хранилищем объектов с логикой,
Я такого нигде не писал. Я всего лишь говорил что данные (строки) типизированы. О каких объектах с логикой может идти речь, если мы, скажем, выполняем операцию join (ты разве не предлагал LINQ использовать )? Откуда вобще вылезли какие то объекты с логикой?
AVK>>Например ввиде .NET сборок.
_FR>Вернее, класс в сборке, помеченный, например, каким-нить аттрибутом, определяет таблицу?
Здравствуйте, eao197, Вы писали:
AVK>>Тогда другая проблема — невозможность длинных транзакций. Возьмем почтовый клиент — предположим мы в процессе редактирования сообщения начали транзакцию. В этот момент сетевой блок получил новые письма. Так вот — ему придется курить пока мы не закроем окно редактирования.
E>Ну просто для таких вещей требования заранее озвучивать нужно E>А длительные транзакции -- это весьма серьезное требование.
Что озвучивать? Я не уверен что это обязательно нужно. Просто напоминаю чего мы лишаемся в случае обеспечения serializable read путем блокировок.
E>Кстати о длительных транзакциях. Если в ней будет изменяться всего один объект (письмо в почтовой программе), то возможен еще один подход. Транзакции кратковременные, но вот объекты можно специально помечать как временно изъятые (по-моему, в какой-то ООСУБД это дело называлось check out). Т.е., перед началом редактирования письма ты делаешь его checkout. В этот момент никто не может его изменить или удалить. Затем ты фиксируешь его новое значение и выполняешь возврат (checkin).
Ну и? Кто эти чекины анализирует и на что они влияют? Нельзя выполнить запись в зачекаутенный объект? Или что то иное?
AVK>>Ну вот и получиться sql-сервер.
E>AFAIK, в BerkeleyDB делается так: весь кэш и все данные открытой БД размещаются в разделяемой памяти. Процессы, которые с ней работают, используют обычную синхронизацию для доступа к этой памяти. Достаточно просто и этой схеме до SQL сервера еще расти и расти.
Здравствуйте, AndrewVK, Вы писали:
AVK>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов.
Такое дело есть, перспективное.
Начну издалека.
Система которой я занимаюсь, представляет собой набор приложений, которые самостоятельно работают с настольной базой.
Наблюдается такая тенденция, которая вроде-бы ведёт к созданию одного супер-приложения. Но по этому пути она пойти неможет, так как долго будет грузиться, много занимать, сложно поддерживать и невыгодно продавать.
Остаётся модель системы из нескольких процессов и с одной базой.
Что нужно нового?
Нужны не триггеры а хуки. Нужно чтобы я в одном приложении мог пасти на изменения, определённую ветку данных (как папку в файловой системе) сделанные в другом приложении. Т.е. нужен калбэк-интерфейс.
ещё добавлю, что я уверен в перспективности такого подхода к эволюции подобных систем. а их довольно много.
Здравствуйте, AndrewVK, Вы писали:
E>>Кстати, Андрей, ты в курсе, что есть еще один механизм обеспечения транзакционности, без лога? Это когда новые значения объектов при изменении в транзакции записываются на новое место.
AVK>Новые значения объектов в отдельном месте это и есть лог.
Я думал, что лог, это когда сначала записываем в лог транзакции, а затем в файл БД.
E>> Если в течении транзакции они обновляются, то обновляются уже на новом месте. Фиксация транзакции заключается в изменении ссылки на значение объекта
AVK>Какого объекта? Откуда у вас все время какие то объекты вылазят?
Ну а как назвать то, что ты будешь в своей БД хранить?
Даже если ты хранишь строки реаляционной таблицы или туплы какие-нибудь, даже если ты переписываешь всю страницу БД целиком, это общего принципа не меняет.
AVK> Ты имеешь ввиду создание копий страниц В+ дерева и коррекция ссылок в родительском узле и соседях? Думаю за счет сиков это будет медленнее чем просто переписать страницу поверх. И не забывай об индексах.
Да здесь то же самое. Представь, что в ссылки в индексах хранят не прямой адрес страницы, а ее идентификатор. А по идентификатору через специальную relocation table ты находишь адрес. Тогда, при необходимости перезаписи страницы БД (индекс это или страница с объектами/строками/туплами), ты просто записываешь страницу в новое место и правишь ссылку на нее в memory-relocation-table. При фиксации транзакции сбрасываешь memory-relocation-table на диск. И все. Сложность только в атомарности изменения relocation table.
Достичь этого можно, например, двумя способами:
— write ahead log для изменения relocation table. Здесь все понятно;
— две копии relocation table с контрольными суммами и метками времени. При фиксации транзакции изменяешь обе с увеличением метки времени. При сбое и восстановлении считываешь обе -- если они с корректными контрольными суммами, то актуальное значение в той, у которой метка времени больше.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
E>>Кстати о длительных транзакциях. Если в ней будет изменяться всего один объект (письмо в почтовой программе), то возможен еще один подход. Транзакции кратковременные, но вот объекты можно специально помечать как временно изъятые (по-моему, в какой-то ООСУБД это дело называлось check out). Т.е., перед началом редактирования письма ты делаешь его checkout. В этот момент никто не может его изменить или удалить. Затем ты фиксируешь его новое значение и выполняешь возврат (checkin).
AVK>Ну и? Кто эти чекины анализирует и на что они влияют? Нельзя выполнить запись в зачекаутенный объект? Или что то иное?
Да, нельзя выполнить запись и нельзя удалить. Я же написал. Изменять его может только тот, кто отчекаутил.
Причем, что хорошо, эти метки checkout-а можно прямо в БД записывать.
В той ООБД (вот не помню, кажется POET) checkout-ы использовались для действительно длительных операций (больше нескольких дней).
E>>AFAIK, в BerkeleyDB делается так: весь кэш и все данные открытой БД размещаются в разделяемой памяти. Процессы, которые с ней работают, используют обычную синхронизацию для доступа к этой памяти. Достаточно просто и этой схеме до SQL сервера еще расти и расти.
AVK>А как быть если данных > 2Г?
"Под всеми данными открытой БД" я подразумевал не содержимое БД, а управляющие структуры (ну там список активных процессов, работающих с БД, описания транзакций, блокировок и прочего). Непосредственно в ОП находятся только закэшированные страницы, а размером кэша можно правлять. В таком режиме можно хоть с терабайтными базами работать.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
AB>>Триггеры для того, чтобы пользователь мог редактировать данные в режиме таблицы как из самой Access AVK>Я правильно понимаю, что настольная БД должна, по твоему, редактироваться из Access?
Нет. Просто мне бывает частенько нужно обработать массив данных и забыть о нем. Вот тут подобные способы редактирования начинают рулить ибо данные приходят в каком попало виде — тексты, Excel, dbf и т.д.
Так же, бывает, что хватает и самого аксеса как оболочки для для всех манипуляций с данными, когда не требуется всяких красявостей. Мы же говорим о настольной БД?
AB>> Можно и без них, но иногда хочется маленького счастья — внес проплату прямо ручками и в режиме таблицы, а она автоматически раскидалась по счетам, например. А так как записей всего 100-200 тыс — это не сильно заметно. AVK>Ну и чего тут сложного? Поскольку у нас in process, то просто подвешиваемся на какое нибудь событие или делаем где нибудь в объекте виртуальный метод.
Ничего. Кроме того, что у тебя под рукой может не быть среды и ты находишься в тьмутаракани у клиента, а ему захотелось сделать к-л финт ушами. По этому, хотелось бы вынести наибольшую часть логики в БД и иметь возможность редактировать ее из внешней, по отношению к приложению, среды. Так что ни о каком in process тут даже и речи не идет (по крайней мере, я 10 раз подумаю, прежде чем подпишусь на in process движок, и, скорее всего, откажусь даже в жертву ресурсам).
AB>>По поводу каки. Интеграция с другими продуктами офиса, AVK>Интеграцию можно производить на разных уровнях, не обязательно на уровне БД.
Можно, но если эта возможность уже есть и есть именно на этом уровне и ей можно воспользоваться, то почему бы и нет?
AB>> наличие драйвера в стандартном MDAC, AVK>В случае JET отсутствуют начиная с версии 2.6
Я отстал от жизни.
AB>> автоматическое обновление с WindowsUpdate, AVK>Отсутствует
Хм. Имелось ввиду обновление компонентов офиса. Или и это теперь отсутствует? Я просто не в курсе — я настроил обновление раз в сутки и забыл о нем.
AB>> наличие оболочки почти на каждой машине, AVK>Для десктопа не критично.
Не критично, но это соломка на нештатные ситуации, которая греет душу.
AB>> выбор команды RSDN... AVK>Чего???
Janus.
З.Ы. Я не буду доказывать, что Access — это круто. Это просто мой выбор, проверенный моим временем, моим опытом и почти адекватный моим задачам для настольных БД.
Не так давно посмотрел на SQLite в связке с Trac. Попробуйте экспортировать базу в текстовый дамп и импортировать ее обратно. В итоге вся вики-разметка, базирующаяся на количестве пустых строк, съезжает. Может, движок и хороший, но романтический момент упущен.
До этого смотрел на Advantage — просто много ненужных мне наворотов, хотя достойно внимания.
Здравствуйте, Cyberax, Вы писали:
>> А нужна ли изоляция транзакций? Нужен ли универсальный язык запросов? C>Зависит от задачи. В персональном дневнике — может и не нужно. В C>хранилище почтовых сообщений — нужно с большой вероятностью.
Зачем там изоляция? Зачем язык запросов?
>> Нужны ли собственные метаданные? Нужна ли механика коммуникации? Нужен ли >> прикладной слой преобразования типов БД в типы среды исполнения >> прикладного кода? C>Зависит от желаний и потребностей.
Какие желания и потребности могут привести к подобным требованиям? По пунктам, плиз.
>> C>У меня в одном проекте файл БД — это документ, который открывается >> C>программой. >> Классно. Но я ведь не про твой проект спрашиваю. C>Я просто приводил use-case, когда это может быть нужно.
Ну как то у меня немножко другая модель того, для чего я предполагаю использование сабжа. О возможности хранения в ней документов я как то не предполагал. Опять же, даже если и так, то ворд, к примеру, не особенно то позволяет один файл редактировать нескольким экземплярам.
>> Это уже не суть важно. Я ведь не про реализацию спрашиваю. C>Стоит посмотреть даст ли compile-time планирование какие-то существенные C>преимущества — может проще при старте программы скомпилировать все C>SQL-запросы.
Не, я не про планирование, я про compile time checks типов. А планирование нет, скорее всего ничерта не даст.
C>Уточню, база сообщений Outlook'а — это фактически целая БД с C>транзакциями, языком запросов и сортировки.
Ну МС может себе это позволить
>> И? Ты хочешь сказать что без текстового языка запросов эту задачу не решить? C>Все равно нужен механизм _настриваемых_ запросов (то есть я могу выбрать C>сортировку по custom-ной колонке "ДатаДляМенеджера" и по колонке "Статус").
Для этого не нужен полноценный язык запросов. И, в любом случае, это может быть отдельный компонент, потому что такой язык нужен далеко не всегда.
C>Чистым compile-time'ом не обойдешься, нужно делать хотя бы что-то типа C>ICriteria. А написать транслятор [x]QL в дерево критерия — задача не C>очень сложная.
Но не всегда эту задачу нужно вобще решать.
>> А я говорю про легковесность? Я говорю лишь про выкидывание ненужного >> для десктопа функционала. Реструктуризация для него пожалуй даже нужнее >> чем для клиент-сервера. C>Просто я не вижу лишнего в функциональность БД.
Чувствуешь насколько все запутаннее стало? А если нужно сортировать понескольким полям, да еще и с разным направлением?
_FR>Как, кстати, в твоём варианте, сделать сортировку без учёта регистра? Вот так: _FR>
Здравствуйте, AndrewVK, Вы писали:
AVK>Когда то давно, когда PC только появлялись, было такое явление как настольные СУБД. Потом их практически вытеснили SQL-сервера, и если они и есть где, то это в основном развитие старых продуктов. AVK>SQL-сервера это конечно здорово, однако по прежнему есть ряд применений, для которых их навороты не нужны, равно как не нужен оверхед, связанный с многопользовательским доступом и сложное администрирование.
Ничего плохого во многопользовательском доступе нет. Учитывая, что приложение может выступать как снрвер приложений. AVK>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов. Более конкретный список вопросов: AVK>1) in process или out of process?
Однозначно in process но с поддержкой транзакций, версионности
AVK>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc
Все тоже самое. Хранение в одном файле предпочтительней AVK>3) Описание метаданных
Наверное это за надстройкой. БД должна давать минимум функций, а прикладной код делать объектную надстройку. AVK>4) Способ формирования запросов
По мне и навигационного доступа вполне достаточно, во всяком случае в 1С я их практически не использую ни в каких вариантах. AVK>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
БД отвечает за запись чтение, транзакции, блокировки итд. Прикладной код за все остальное.
Вполне достаточно, для решения большинства задач.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
_FR>>Это я понимаю. Но IDataReader, например, как часто ты используешь? AVK>Часто. Значительно чаще чем DataSet. _FR>> Для каких задач? AVK>Для задач работы с БД.
Ну я, нарпимер, для "задач работы с БД" от разграничения прав уже уже отказались. Когда IDataReader необходим?
_FR>> С XmlReader — немного другое. Он один позволяет пробегать по совершенно различным сущностям — он деревообразный, AVK>Нет, он плоский. Потому что бежит по плоскому файлу. _FR>> по нему осуществляется доступ к объектам разных типов. AVK>Это не играет никакой роли.
Он пробегает по неплоским данным. По данным с различной структурой. Вот, например FileStream. Зачем он был бы нужен, имей я возможность в парамтрах OpenFile(…) указать, что мне из него нужно прочитать?
Хотя я, кажется, понял о чём ты. Пусть мне надо закачать данные из базы в свои структуры. Лучше бежать по обдному объекту базы, создавать у себя свою копию и переходить к следующему объекту базы, вместо того, чтоб из базы поулчить с три короба, создать свои три короба, надеятся, что память, выделенная под первые скоро освободиться Тогда ты прав, но при я таком подходе… (*)
_FR>>Ага, а мне показалось, что предлагается, что СУБД уже будет хранилищем объектов с логикой,
AVK>Я такого нигде не писал. Я всего лишь говорил что данные (строки) типизированы. О каких объектах с логикой может идти речь, если мы, скажем, выполняем операцию join (ты разве не предлагал LINQ использовать )? Откуда вобще вылезли какие то объекты с логикой?
Например, в моём типе может быть описано вычисляемое свойство? Скорее, если понял общую идею, место такому свойству не в сборке базы данных, а в бизнес-объектах, (*) которые к объектам, которыми описывается структура БД, никакого отношения не имеет? Верно?
Выходит, что пользователю такой СУБД, надо будет: Описать объекты структуры таблиц в БД.
Описать бизнес-объекты и правила маппинга их на объекты из п.1.
При осуществлении выборок из бизнес-объектов, те, в свою очередь, осуществляют выборку из объектов п.1
Последний пункт мне не нравится.
Мне бы очень помогло, опиши ты как бизнес-объекты связыватся со структурой БД?
... << RSDN@Home 1.2.0 alpha rev. 648>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Anton Batenev, Вы писали:
AB>Нет. Просто мне бывает частенько нужно обработать массив данных и забыть о нем. Вот тут подобные способы редактирования начинают рулить ибо данные приходят в каком попало виде — тексты, Excel, dbf и т.д.
Это не сочитается с типизированным доступом. Тут уж что то одно — либо контроль типов и правка специальными тулзами, либо правка чем попало.
AB>Ничего. Кроме того, что у тебя под рукой может не быть среды и ты находишься в тьмутаракани у клиента, а ему захотелось сделать к-л финт ушами. По этому, хотелось бы вынести наибольшую часть логики в БД и иметь возможность редактировать ее из внешней, по отношению к приложению, среды.
Клиент, логика в БД ... Мы по прежнему о однопользовательской встроенной БД говорим?
AB> Так что ни о каком in process тут даже и речи не идет (по крайней мере, я 10 раз подумаю, прежде чем подпишусь на in process движок, и, скорее всего, откажусь даже в жертву ресурсам).
Братец, но я то совсем про другое спрашивал. меня не интересуют локальные БД, меня интересуют однопользовательские десктопные БД.
AVK>>Интеграцию можно производить на разных уровнях, не обязательно на уровне БД.
AB>Можно, но если эта возможность уже есть и есть именно на этом уровне и ей можно воспользоваться, то почему бы и нет?
Нет ее. Это ты ее предлагаешь реализовать.
AB>>> автоматическое обновление с WindowsUpdate, AVK>>Отсутствует
AB>Хм. Имелось ввиду обновление компонентов офиса. Или и это теперь отсутствует? Я просто не в курсе — я настроил обновление раз в сутки и забыл о нем.
Не у всех есть офис, да еще и с автообновлением.
AB>>> выбор команды RSDN... AVK>>Чего???
AB>Janus.
И что ты мне хочешь про него рассказать?
AB>З.Ы. Я не буду доказывать, что Access — это круто. Это просто мой выбор, проверенный моим временем, моим опытом и почти адекватный моим задачам для настольных БД.
Ну вот а для нас он оказался не полностью адекватен. Поэтому хочется лучшего, а не того же самого.
Здравствуйте, eao197, Вы писали:
E> Я думал, что лог, это когда сначала записываем в лог транзакции, а затем в файл БД.
В БД записывать не обязательно, если механика позволяет учитывать содержимое в памяти.
AVK>>Какого объекта? Откуда у вас все время какие то объекты вылазят?
E>Ну а как назвать то, что ты будешь в своей БД хранить?
Данные.
E>Даже если ты хранишь строки реаляционной таблицы или туплы какие-нибудь, даже если ты переписываешь всю страницу БД целиком, это общего принципа не меняет.
Вот и хотелось бы без конкретики, а то непонятно. У тебя в голове есть какая то модель, а вот в моей она отсутствует, поэтому иногда я не могу понять о чем идет речь.
AVK>> Ты имеешь ввиду создание копий страниц В+ дерева и коррекция ссылок в родительском узле и соседях? Думаю за счет сиков это будет медленнее чем просто переписать страницу поверх. И не забывай об индексах.
E>Да здесь то же самое. Представь, что в ссылки в индексах хранят не прямой адрес страницы, а ее идентификатор. А по идентификатору через специальную relocation table ты находишь адрес. Тогда, при необходимости перезаписи страницы БД (индекс это или страница с объектами/строками/туплами), ты просто записываешь страницу в новое место и правишь ссылку на нее в memory-relocation-table. При фиксации транзакции сбрасываешь memory-relocation-table на диск. И все.
Я же тебе объяснил — перезапись страницы значительно дешевле чем правка ссылок в нескольких страницах. Что же касается отдельной таблицы пересчета адресов то это пустой расход памяти и диска, раздувание файла БД, лишняя косвенность и еще одна возможность для сбоев.
Здравствуйте, Serginio1, Вы писали:
S>Ничего плохого во многопользовательском доступе нет. Учитывая, что приложение может выступать как снрвер приложений.
Это выходит за рамки описываемой задачи. Многопользовательский доступ это очень дорогая во всех смыслах технология. Если речь о сервере приложений, то там как раз доступ однопользовательский, как правило, хоть и параллельный.
AVK>>3) Описание метаданных S> Наверное это за надстройкой. БД должна давать минимум функций, а прикладной код делать объектную надстройку.
Т.е. данные внутри БД описываются системой типов самой БД, а прикладной код должен самостоятельно выполнять конверсию? И что мы выигрываем при этом?
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, GlebZ, Вы писали:
AVK>>>О первичных ключах: AVK>>>1) Допустимо ли требование обязательного наличия первичного ключа? AVK>>>2) Допустимо ли требование несоставного первичного ключа? AVK>>>3) Допустимо ли требование первичного ключа определенного типа? GZ>>Лучше сразу спросить, нужен ли синтетический ключ. IMHO нужен, для однозначной идентификации объекта в памяти и его состояния на диске.
AVK>В п.3 несколько более жесткое требование.
Да тоже самое. Синтетика всегда делается одного типа для унификации.
AVK>>>4) Допустимо ли требование первичного ключа типа GUID? GZ>>Зависит от типа задачи. Я, например, люблю GUID.
В случае, если нужно синхронизироваться в архитектуре datacenter, то нужно по крайней мере поддерживать идентификацию принятую на сервере. (вопрос уже как, это второй. Можно и через таблицу соответсвий.)
AVK>Тип задачи — настольная однопользовательская БД. AVK>>>О расширяемости: AVK>>>Что должно быть расширяемо в сабже? GZ>>Есть ли у тебя наследование? AVK>Пока речь шла только о типизации. Про объектность это еще надо обсуждать.
GZ>>Ключ может быть синтетическим хешем. В этом случае это у тебя будет прямой доступ. Ну и есно декларативные запросы подгружающие графы. AVK>Т.е ОО-БД?
Ну если пока это не обсуждать, то в XQuery и в LINQ(DLINQ) есть подгрузки графов(для Linq см. Including). И оба умеют работать с реляционными базами данных. А штука чрезвычайно удобная(если база данных на таких запросах не подкачает).
AVK>>>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов? GZ>>Нужен другой. Для поддержки слабоструктурированных данных. AVK>Тебе не кажется что это выходит за рамки БД, особенно настольной?
Как раз для настольной я думаю и не выходит.В эпоху настольных систем были интересные навигационные реляционные базы данных, типа Clarion и т.п. Чрезвычайно эффективные, особенно учитывая что работали под MSDOS. Выдавили их SQL системы в силу того, что они не обеспечивают совместимость с SQL. 1C, как раз на этом сильно и погорел. Навигация для удаленных систем смертеподобна.
GZ>> Как я уже упоминал, типа LINQ или XQuery AVK>lINQ это не текстовый язык запросов, это языковая конструкция.
Не цепляйся за слова. Главное смысл.
AVK>>>2) Что лучше — выборки или навигационный способ(курсоры). GZ>>Все вместе. AVK>Они взаимозаменяемы. Если есть один, то другой может быть реализован ввиде библиотеки.
Если ты имеешь ввиду курсоры, то да. Это один механизм. Если мы делаем переходы по ссылкам, то это уже другая песня. Вообще курсоры как таковые малоинтересны. В случае многопользовательской системы, курсор это достаточно сложная функциональность, которая уберегает возвращаемые данные от изменений пользователями. У нас, как я понял, такой задачи на горизонте не стоит. Легче оперировать выборками, и получать объекты которые уже можно спокойно обрабатывать. А вот далее, с навигационным доступом со скачкой по ссылкам, можно наделать делов.
Здравствуйте, _FRED_, Вы писали:
_FR>Ну я, нарпимер, для "задач работы с БД" от разграничения прав уже уже отказались. Когда IDataReader необходим?
Всегда, когда не подходит DataSet. А неподходит он, когда у нас есть собственная ОО-модель данных. Ты BLToolkit смотрел?
_FR>Он пробегает по неплоским данным.
Для ридера они плоские. Неплоскость появляется только при интерпретации.
_FR>Хотя я, кажется, понял о чём ты. Пусть мне надо закачать данные из базы в свои структуры. Лучше бежать по обдному объекту базы, создавать у себя свою копию и переходить к следующему объекту базы, вместо того, чтоб из базы поулчить с три короба, создать свои три короба, надеятся, что память, выделенная под первые скоро освободиться
А теперь еще вспомни, что есть предложение (которое ты поддержал) вобще отказаться от нетипизированных хранилищ.
AVK>>Я такого нигде не писал. Я всего лишь говорил что данные (строки) типизированы. О каких объектах с логикой может идти речь, если мы, скажем, выполняем операцию join (ты разве не предлагал LINQ использовать )? Откуда вобще вылезли какие то объекты с логикой?
_FR>Например, в моём типе может быть описано вычисляемое свойство?
А нафига оно? Считать это вобщем то не задача БД. Можно и отдельно посчитать, можно и в самом объекте, только к БД это не имеет никакого отношения.
_FR> Скорее, если понял общую идею, место такому свойству не в сборке базы данных, а в бизнес-объектах, (*) которые к объектам, которыми описывается структура БД, никакого отношения не имеет? Верно?
Ну вроде того.
_FR>Выходит, что пользователю такой СУБД, надо будет: _FR> _FR>Описать объекты структуры таблиц в БД. _FR>Описать бизнес-объекты и правила маппинга их на объекты из п.1. _FR>При осуществлении выборок из бизнес-объектов, те, в свою очередь, осуществляют выборку из объектов п.1 _FR>_FR>Последний пункт мне не нравится.
пп.2 и 3 выходят за рамки данного обсуждения. Но может быть по всякому. Можно например результат п.1 скинуть в массив и сразу отобразить в гриде.
_FR>Мне бы очень помогло, опиши ты как бизнес-объекты связыватся со структурой БД?
Здравствуйте, _FRED_, Вы писали:
_FR>Да, если будет индекс, + параметр IComparer<T>, то, ИМХО, просто здорово. _FR>Но, в твоём варианте, не будет составных индексов, так?
Индексы будут, не будет составных OrderBy. Хотя и это можно при желании добавить.
Здравствуйте, GlebZ, Вы писали:
AVK>>В п.3 несколько более жесткое требование. GZ>Да тоже самое. Синтетика всегда делается одного типа для унификации.
Я то с тобой, пожалуй, соглашусь. Но мне встречались товарищи, с тобой несогласные категорически.
GZ>В случае, если нужно синхронизироваться в архитектуре datacenter, то нужно по крайней мере поддерживать идентификацию принятую на сервере. (вопрос уже как, это второй. Можно и через таблицу соответсвий.)
Тока с сабжем это немного общего имеет.
AVK>>Т.е ОО-БД? GZ>Ну если пока это не обсуждать, то в XQuery и в LINQ(DLINQ) есть подгрузки графов(для Linq см. Including).
В LINQ нет никакой подгрузки. Это языковый механизм, как реализацию напишешь так и будет. А DLINQ это совсем не то, о чем речь.
AVK>>lINQ это не текстовый язык запросов, это языковая конструкция. GZ>Не цепляйся за слова. Главное смысл.
Вот за смысл я как раз и цепляюсь. Ты постоянно пытаешься трактовать LINQ как еще один текстовый язык запросов, а это совсем не так.
AVK>>Они взаимозаменяемы. Если есть один, то другой может быть реализован ввиде библиотеки. GZ>Если ты имеешь ввиду курсоры, то да. Это один механизм. Если мы делаем переходы по ссылкам, то это уже другая песня.
А делаем ли? Типизированная БД <> ООБД. А ты постоянно скатываешься на последнюю.
GZ> Вообще курсоры как таковые малоинтересны. В случае многопользовательской системы, курсор это достаточно сложная функциональность, которая уберегает возвращаемые данные от изменений пользователями. У нас, как я понял, такой задачи на горизонте не стоит. Легче оперировать выборками, и получать объекты которые уже можно спокойно обрабатывать.
Опять ты думаешь в терминах ОО. База совсем не обязана создавать выборки каждый раз. Если нам нужно простопроанализировать данные, а не куда нибудь показать, поднимать сразу все в память никому не нужно, достаочно просто по данным пробежаться.
GZ> А вот далее, с навигационным доступом со скачкой по ссылкам, можно наделать делов.
Навигационный доступ в пределах курсора (навигация абсолютно плоская). Внешние ссылки это уже другой курсор.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>Ничего плохого во многопользовательском доступе нет. Учитывая, что приложение может выступать как снрвер приложений.
AVK>Это выходит за рамки описываемой задачи. Многопользовательский доступ это очень дорогая во всех смыслах технология. Если речь о сервере приложений, то там как раз доступ однопользовательский, как правило, хоть и параллельный.
Ничто не мешает сделать многопользовательский доступ, но на уровнем удаленных методов. В большинстве случаев этого достаточно. AVK>>>3) Описание метаданных S>> Наверное это за надстройкой. БД должна давать минимум функций, а прикладной код делать объектную надстройку.
AVK>Т.е. данные внутри БД описываются системой типов самой БД, а прикладной код должен самостоятельно выполнять конверсию? И что мы выигрываем при этом?
ООП подход. БД нужно только знание IComparer для индексов и длина записи. В большинстве случаев поля будут иметь неопределенный тип итд.
БД отвечает только за хранение. Надстройка над реляционной БД самый выгодный подход, но при этом БД должна быть внутренней, при этом мы можем иметь быстрый доступ, ООП надстройку, преобразование полей записи на уровне свойств итд.
Я смотрю на такую БД с точки зреня 1С, Паруса , акзапты. А так и ДБФ выше крыши.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>>>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов. GZ>>Все равно получается вопрос неконкретный. AVK>Лишний повод включить фантазию
У меня сейчас как раз такие фантазеры и наваяли большую, в общем, чудо. Большой набор больших механизмов без всякого понятия а для чего ж они нужны вообще всей предметной задаче. Так что у меня на такие слова нервный тик.
Попробуй привести несколько примеров где данная БД может быть использована.
GZ>> Зависит от того, является ли база данных самостоятельной для desktop приложения, или же использоваться как кэш для smart client или datacenter. AVK>А зачем для кеша какая то особенная БД?
Минимум она должна держать идентификацию совместимую с основным сервером идентификацию.
AVK>>>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc GZ>>Файл один. Это был и остался лучший способ, поскольку существуют оптимизации по месту хранения(типа пытаемся читать как можно последовательней). AVK>На физическое расположение файла на диске все равно прикладная программа не влияет.
Этим и БД в принципе не увлекаются(хотя такие попытки были). Они работают в предположении что OS сохранила файл последовательно. И это у них неплохо получается.
Здравствуйте, AndrewVK, Вы писали:
_FR>>Ну я, нарпимер, для "задач работы с БД" от разграничения прав уже уже отказались. Когда IDataReader необходим? AVK>Всегда, когда не подходит DataSet. А неподходит он, когда у нас есть собственная ОО-модель данных. Ты BLToolkit смотрел?
Понял. Я вначале не так понял задачи, которые должен решать движок БД — казалось, что в неё планируется включить поддержку бизнес-объектов, а это не так, как выяснилось. И отлично. Теперь уверен, что курсоров хватит.
AVK>>>Я такого нигде не писал. Я всего лишь говорил что данные (строки) типизированы. О каких объектах с логикой может идти речь, если мы, скажем, выполняем операцию join (ты разве не предлагал LINQ использовать )? Откуда вобще вылезли какие то объекты с логикой? _FR>>Например, в моём типе может быть описано вычисляемое свойство? AVK>А нафига оно? Считать это вобщем то не задача БД. Можно и отдельно посчитать, можно и в самом объекте, только к БД это не имеет никакого отношения.
Старая дуратская привычка поделиться логикой с БД Не прав.
AVK>Ну вроде того.
_FR>>Выходит, что пользователю такой СУБД, надо будет:
… AVK>пп.2 и 3 выходят за рамки данного обсуждения. Но может быть по всякому. Можно например результат п.1 скинуть в массив и сразу отобразить в гриде.
Ага. Это понятно.
_FR>>Мне бы очень помогло, опиши ты как бизнес-объекты связыватся со структурой БД? AVK>Не в этой ветке
В такой постановке — да. Тогда, покажи пример класса, описывающего таблицу? Вернее, описывающего строку таблицы. Интересует вот что.
Каждое свойство класса, описывающего таблицу, помеченно каким-либо аттрибутом — это "колонка" таблицы. Имеет-ли смысл держать в таком классе другие свойства? Какие? Может, это и не класс вовсе, а интерфейс\абстрактный класс с декларацией свойств?
Имеет ли смысл строить иерархию таких классов\интерфейсов для обозначения таблиц со схожей структурой?
... << RSDN@Home 1.2.0 alpha rev. 648>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, AndrewVK, Вы писали:
GZ>>В случае, если нужно синхронизироваться в архитектуре datacenter, то нужно по крайней мере поддерживать идентификацию принятую на сервере. (вопрос уже как, это второй. Можно и через таблицу соответсвий.) AVK>Тока с сабжем это немного общего имеет.
Ну вот. Ограничиваем применимость сабжа?
AVK>>>lINQ это не текстовый язык запросов, это языковая конструкция. GZ>>Не цепляйся за слова. Главное смысл. AVK>Вот за смысл я как раз и цепляюсь. Ты постоянно пытаешься трактовать LINQ как еще один текстовый язык запросов, а это совсем не так.
Возьми espresso, и у тебя есть тектовой язык запросов. Немного лучше HQL и немного хуже XQuery. Смысл то у них, одинаковый.(а я говорю именно о запросах которые еще не обработаны препроцессором в функциональный вид).
AVK>>>Они взаимозаменяемы. Если есть один, то другой может быть реализован ввиде библиотеки. GZ>>Если ты имеешь ввиду курсоры, то да. Это один механизм. Если мы делаем переходы по ссылкам, то это уже другая песня. AVK>А делаем ли? Типизированная БД <> ООБД. А ты постоянно скатываешься на последнюю.
Уж очень мне хочется. Наболело. Повторю. Lazy Load в условиях локальной базы данных операция дешевая. Хочешь еще большей дешевизны при массовых операциях, пользуй запросы.
А на OODB(хоть это и моя больная тема) я еще не скатывался.
AVK>Опять ты думаешь в терминах ОО. База совсем не обязана создавать выборки каждый раз. Если нам нужно простопроанализировать данные, а не куда нибудь показать, поднимать сразу все в память никому не нужно, достаочно просто по данным пробежаться.
Сделай запрос с делегатом, который будет обеспечивать все изменения и все подсчеты которые тебе нужны. Сделай так, чтобы БД предоставила все необходимые данные для этого, и синхронизировала состояния между памятью и диском.
Поясню последний пункт. Если мы делаем изменение с объектом, то это изменение должно отражаться на той же сущности(не важно, назови ее tuple, объект или entity), что и находится в памяти. И точно также именно эта сущность должна предоставляться в процессе запроса, и точно также именно по этой сущности должны работать операции фильтрации и сортировки. Что будет дальше с этими объектами, неважно. Если в них не было изменений, то их вообще можно навесить на WeakReference или потерять.
Зачем keyset? Зачем курсоры? Мы можем дать пользователю единую феню и не мучить его не особо нужным функционалом.
Здравствуйте, AndrewVK, Вы писали:
E>>Ну а как назвать то, что ты будешь в своей БД хранить?
AVK>Данные.
Ну вот считай, что твои данные я называю объектом.
AVK>Вот и хотелось бы без конкретики, а то непонятно. У тебя в голове есть какая то модель, а вот в моей она отсутствует, поэтому иногда я не могу понять о чем идет речь.
EMBEDDED OBJECT ORIENTED DATABASE SYSTEMS FOR JAVA AND CSHARP -- смотреть раздел Shadow transaction mechanism.
AVK>Я же тебе объяснил — перезапись страницы значительно дешевле чем правка ссылок в нескольких страницах. Что же касается отдельной таблицы пересчета адресов то это пустой расход памяти и диска, раздувание файла БД, лишняя косвенность и еще одна возможность для сбоев.
Ты не понял полностью. Нет перезаписи страницы.
А таблица пересчета адресов -- это очень быстро. И достаточно компактно. Да и лишних возможностей для сбоев я не вижу.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
AVK>Я имею ввиду собственно то, что под этим обычно стандартно понимают.
Обычно под этим понимают режимы работы планировщика, разруливающего конкурентные транзакции... Пессиместический не позволяет писать, а оптимистический позволяет, но откатывает всю транзакцию в случае конфликта.
AVK> Оптимистичные транзакции, это когда пишем в лог, потом пишем в БД, а если откатываемся, то делаем над БД обратные операции.
Это называется Write Ahead Logging.
AVK> Пессимистичные, это когда лог и новые версии накапливаем в памяти, а при коммите вносим изменения в БД.
Если я правильно помню, то этот режим называется No Redo/No Undo Logging, но это надо смотреть...
E> Это когда новые значения объектов при изменении в транзакции записываются на новое место. Если в течении транзакции они обновляются, то обновляются уже на новом месте. Фиксация транзакции заключается в изменении ссылки на значение объекта (ссылка на старое расположение ссылкой на новое расположение).
Эта техника называется Shadow Copying, если я правильно помню, применялась в System/R и других приличных местах до знаменитой работы Мохана по ARIES в которой он доказал эффективность WAL в сочетании с Undo/Redo...
[skip, как путь ведущий в никуда]
AB>>З.Ы. Я не буду доказывать, что Access — это круто. Это просто мой выбор, проверенный моим временем, моим опытом и почти адекватный моим задачам для настольных БД. AVK>Ну вот а для нас он оказался не полностью адекватен. Поэтому хочется лучшего, а не того же самого.
Здравствуйте, AndrewVK, Вы писали:
AVK>О первичных ключах: AVK>1) Допустимо ли требование обязательного наличия первичного ключа? AVK>2) Допустимо ли требование несоставного первичного ключа? AVK>3) Допустимо ли требование первичного ключа определенного типа? AVK>4) Допустимо ли требование первичного ключа типа GUID?
Я — за принудительно введенный GUID.
Доп. расходов не так уж и много, зато минимум проблем для автоматических алгоритмов репликации/мерджа и прочих вещей, полезных для встроенных СУБД.
Опять же упрощается реализация FK; заодно появляется возможность отказаться от произвольных JOIN и заставить джониться только по FK. AVK>О расширяемости: AVK>Что должно быть расширяемо в сабже?
AVK>О keysets: AVK>1) Допустимо ли встраивание этой механики в движек БД. AVK>2) Достаточно ли самого простого варианта, или нужна возможность подкрузки в кейсет части данных? AVK>3) Нужна ли многостадийная загрузка или подгрузка в 2 стадии — кейсет и остальные данные? Или может еще какой вариант?
AVK>О запросах подробнее: AVK>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов?
Все зависит от того, что будет клиентом этой СУБД. Если Pure .Net — то 100% Linq, и никаких гвоздей. Если что-то более кроссплатформенное — то текстовые запросы. AVK>2) Что лучше — выборки или навигационный способ(курсоры).
Лучше, наверное, все же выборки. Они позволяют лучше масштабировать производительность: при изменении статистики декларативный движок может сменить план запроса. Навигационный план запроса, оптимизированный девелопером для случая "товаров много больше, чем заказов", станет узким местом через полгода эксплуатации. AVK>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль?
А можно попонятнее? AVK>О метаданных: AVK>1) Допустим ли отказ от специфичных для БД метаданных в пользу метаданных, встроенных в платформу?
Наверное, да. AVK>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД?
Имеется в виду отказ от byte[]? Нет, недопустим. AVK>3) Должны ли типы хранится в БД вместе с данными?
Да, крайне желательно. AVK>О деплойменте: AVK>Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек?
Крайне желательно иметь хорошие возможности реструктуризации. Причем я бы начал с реструктуризации копированием вместо реструктуризации "по месту". Т.е. при запуске приложение обнаруживает устаревшую версию БД, создает новую пустую БД новой версии и выполняет импорт из старой в новую. Затем старая версия дропается. Исходя из этого, я думаю, что в движок должны быть встроены средства, облегчающие такой импорт — т.е. simple yet powerful data transfer toolset. Надо помнить о том, что миграция версий структуры бывает не только когда мы запускаем новое приложение над его же старым файлом — это может быть копирование из БД другого пользователя, етк.
Помимо реструктуризации я бы обязательно рассмотрел мердж изменений, сделанных в разных копиях. Очень часто востребованная штука.
Вопросы бэкапа тоже стоило бы рассмотреть. Ну, и, собственно, всё.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Anton Batenev, Вы писали:
AB>Ничего. Кроме того, что у тебя под рукой может не быть среды и ты находишься в тьмутаракани у клиента, а ему захотелось сделать к-л финт ушами.
Угу, а если завтра война?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, AndrewVK, Вы писали:
S>Я — за принудительно введенный GUID. S>Доп. расходов не так уж и много, зато минимум проблем для автоматических алгоритмов репликации/мерджа и прочих вещей, полезных для встроенных СУБД. S>Опять же упрощается реализация FK; заодно появляется возможность отказаться от произвольных JOIN и заставить джониться только по FK.
А если еще добавить ссылку в объекте на родителя то получиться почти сетевая модель
хъ AVK>>1) Допустим ли отказ от специфичных для БД метаданных в пользу метаданных, встроенных в платформу? S>Наверное, да.
Для .NET only хранилища по моему тоже.
AVK>>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД? S>Имеется в виду отказ от byte[]? Нет, недопустим.
+
AVK>>3) Должны ли типы хранится в БД вместе с данными? S>Да, крайне желательно.
+ AVK>>О деплойменте: AVK>>Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек? S>Крайне желательно иметь хорошие возможности реструктуризации. Причем я бы начал с реструктуризации копированием вместо реструктуризации "по месту". Т.е. при запуске приложение обнаруживает устаревшую версию БД, создает новую пустую БД новой версии и выполняет импорт из старой в новую. Затем старая версия дропается. Исходя из этого, я думаю, что в движок должны быть встроены средства, облегчающие такой импорт — т.е. simple yet powerful data transfer toolset. Надо помнить о том, что миграция версий структуры бывает не только когда мы запускаем новое приложение над его же старым файлом — это может быть копирование из БД другого пользователя, етк.
S>Помимо реструктуризации я бы обязательно рассмотрел мердж изменений, сделанных в разных копиях. Очень часто востребованная штука.
S>Вопросы бэкапа тоже стоило бы рассмотреть. Ну, и, собственно, всё.
+
AndrewVK wrote: > Ну и? Что я должен был увидеть?
Прикладной код (редактирование и т.п.) отделен от логики транзакций.
Например, мы можем без всякого изменения кода отредактировать пачку из
10 писем, а потом разом сохранить.
Здравствуйте, prVovik, Вы писали:
AB>>Ничего. Кроме того, что у тебя под рукой может не быть среды и ты находишься в тьмутаракани у клиента, а ему захотелось сделать к-л финт ушами. V>Угу, а если завтра война?
Война в моем городе случается на много порядков реже, нежели причуды заказчика.
Здравствуйте, _FRED_, Вы писали:
_FR>В такой постановке — да. Тогда, покажи пример класса, описывающего таблицу? Вернее, описывающего строку таблицы.
Ну как то так:
public class TestClass : KeyedObjectBase
{
private string _name;
private string _description;
private int _nonPersistent;
public TestClass(Guid primaryKey) : base(primaryKey)
{
}
[DataMember]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember]
public string Description
{
get { return _description; }
set { _description = value; }
}
[DataMember(false)]
public int NonPersistent
{
get { return _nonPersistent; }
set { _nonPersistent = value; }
}
}
_FR>Каждое свойство класса, описывающего таблицу, помеченно каким-либо аттрибутом — это "колонка" таблицы. Имеет-ли смысл держать в таком классе другие свойства?
По желанию.
_FR> Какие?
Ну, к примеру те же вычисляемые свойства. Или свойства агрегирующие простые типы в более сложные объекты.
_FR> Может, это и не класс вовсе, а интерфейс\абстрактный класс с декларацией свойств?
Сложный вопрос. Я пока не могу дать на него однозначного ответа.
_FR>Имеет ли смысл строить иерархию таких классов\интерфейсов для обозначения таблиц со схожей структурой?
Имеет. Весь вопрос как эту иерархию в итоге отображать на В-деревья в файле. Я лично знаю 3 способа.
Здравствуйте, eao197, Вы писали:
E>>>Ну а как назвать то, что ты будешь в своей БД хранить?
AVK>>Данные.
E>Ну вот считай, что твои данные я называю объектом.
Все сразу?
AVK>>Я же тебе объяснил — перезапись страницы значительно дешевле чем правка ссылок в нескольких страницах. Что же касается отдельной таблицы пересчета адресов то это пустой расход памяти и диска, раздувание файла БД, лишняя косвенность и еще одна возможность для сбоев.
E>Ты не понял полностью. Нет перезаписи страницы.
Вот и плохо что нет. Пойми простую вещь — на диск все равно меньше 512 байти не запишешь, даже если тебе всего 8 байт ссылки надо поправить. Соответственно править ссылки в 3 страницах будет медленнее, нежели перезаписать содержимое одной единственной. А таблица пересчета, спасая от правки ссылок в страницах, привносит свои проблемы.
E>А таблица пересчета адресов -- это очень быстро.
Тем не менее медленнее чем без нее.
E> И достаточно компактно.
Пусть страница 8К. Размер БД 10Г. Итого размер таблицы пересчета = 10Г / 8К * 16 = 20М. Считаешь 20 мег это немного?
E> Да и лишних возможностей для сбоев я не вижу.
Плохо смотришь. Сбой в таблице пересчета абсолютно критичен. Следовательно, внося эту таблицу, мы снижаем надежность системы в целом на вероятность сбоя в таблице пересчета.
Здравствуйте, GlebZ, Вы писали:
AVK>>Тока с сабжем это немного общего имеет. GZ>Ну вот. Ограничиваем применимость сабжа?
Да, конечно. Невозможно сождать эффективную, простую и универсальную БД одновременно.
AVK>>Вот за смысл я как раз и цепляюсь. Ты постоянно пытаешься трактовать LINQ как еще один текстовый язык запросов, а это совсем не так. GZ>Возьми espresso, и у тебя есть тектовой язык запросов.
А нафига его брать? Ты пойми — мне не интересны все эти сетафизические предположения, меня интересует практический аспект. А в этом случае LINQ это прежде всего набор фич языка, и декларативные запросы там далеко не самая важная их часть. Если бы их не было вовсе ничего бы принципиально не изменилось, функциональная форма совсем не хуже.
GZ> Немного лучше HQL и немного хуже XQuery. Смысл то у них, одинаковый.
Смысл у них разный.
Вобщем вот определение:
We use the term language integrated query to indicate that query is an integrated feature of the developer’s primary programming languages (e.g., C#, Visual Basic). Language integrated query allows query expressions to benefit from the rich metadata, compile-time syntax checking, static typing and IntelliSense that was previously available only to imperative code. Language integrated query also allows a single general purpose declarative query facility to be applied to all in-memory information, not just information from external sources.
Читайте доки, они рулез.
GZ>Зачем keyset? Зачем курсоры? Мы можем дать пользователю единую феню и не мучить его не особо нужным функционалом.
Затем что причины, почему ООБД до сих пор не получили распространения всем хорошо известны.
Здравствуйте, Sinclair, Вы писали:
AVK>>2) Что лучше — выборки или навигационный способ(курсоры). S>Лучше, наверное, все же выборки. Они позволяют лучше масштабировать производительность: при изменении статистики декларативный движок может сменить план запроса.
Тут только надо помнить насколько это реализуемона практике.
AVK>>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль? S>А можно попонятнее?
А что конкретно непонятно?
AVK>>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД? S>Имеется в виду отказ от byte[]?
Имеется ввиду произвольный формат строки без наличия соответствующего кортежа, описанного в терминах CLR.
S> Нет, недопустим.
Здравствуйте, Sinclair, Вы писали:
S>Речь о том, что все таки нужен вменяемый оптимизатор. В одной руке у него логический план, сформированный именно в виде лямбд. В другой руке — статистика базы (примитивная статистика есть всегда, как минимум в виде Unique и FK Constraints). На выходе именно он должен выдавать план запроса.
Оптимизатор это уже после, когда более менее ясно что требуется. Вопрос в другом — как на основании запроса понять, что физически нужно делать те или иные операции?
AVK>>2) Введение двух форм методов — один с лямбдой, другой с параметрами, описывающими работу с индексом. S>Вторая форма является аналогом хинтов SQL серверов.
Нет. Вторая форма является аналогом SQL. Когда парсер фактически дает описание что выбирать. А хинты отрабатываются уже потом.
S>В полной реляционной модели самые проблемные — это джойны/проекции и группировка. S>Агрегатные запросы мало того, что имеют тенденцию плохо оптимизироваться, они еще и усложняют type inference.
При наличии курсоров агрегаты можно считать в памяти примитивным кодом. А вот выборки все делают намного печальнее, потому что далеко не факт, что выборка влезет в доступную память.
S>Навигационный подход удобен тем, что он никогда не возвращает никаких туплов, не описанных явно в метаданных.
Вот именно.
S>Мораль в том, что надо понять, чего собственно хочется — либо полная реляционная модель (вместе со всеми экзотическими фичами типа non-equality join, джойнов с вычисляемыми полями, агрегатов с окном и прочей экзотикой), либо ограниченная модель, в которой удобно и быстро выполняются некоторые основные операции.
Здравствуйте, GlebZ, Вы писали:
GZ>У меня сейчас как раз такие фантазеры и наваяли большую, в общем, чудо. Большой набор больших механизмов без всякого понятия а для чего ж они нужны вообще всей предметной задаче. Так что у меня на такие слова нервный тик. GZ>Попробуй привести несколько примеров где данная БД может быть использована.
Я пример уже приводил — почтовый клиент.
AVK>>А зачем для кеша какая то особенная БД? GZ>Минимум она должна держать идентификацию совместимую с основным сервером идентификацию.
Здравствуйте, Serginio1, Вы писали:
S> Ничто не мешает сделать многопользовательский доступ, но на уровнем удаленных методов. В большинстве случаев этого достаточно.
Знаешь, я на эту тему с тобой спорить не буду, потому как бесполезно. Можешь делать. Когда сделаешь, тогда и поговорим. А пока что мой опыт свидетельствует, что твои слова далеки от реальности.
AVK>>Т.е. данные внутри БД описываются системой типов самой БД, а прикладной код должен самостоятельно выполнять конверсию? И что мы выигрываем при этом?
S> ООП подход.
??? Это конверсия типов то ООП?
S> БД нужно только знание IComparer для индексов и длина записи. В большинстве случаев поля будут иметь неопределенный тип итд.
Ерунда. Поле в БД не может иметь неопределенный тип, хотя бы потому что на тип завязано построение В+ дерева.
S> Я смотрю на такую БД с точки зреня 1С, Паруса , акзапты.
Здравствуйте, eao197, Вы писали:
AVK>>Все сразу?
E>Блин, Андрей... Чего-то ты к словам цепляешься.
Я не к словам цепляюсь. Просто ты начинаешь говорить о чем то, о чем я даже не спрашивал. Еще раз — я понятия не имею о чем ты сейчас думаешь, поэтоиу додумывать за тебя не имею возможности. Я в исходном вопросе ни о каких объектах не говорил, я вобще предполагал что БД будет все таки реляционной.
E> Ты можешь сам сказать-то что и как ты хочешь записывать в БД и считывать из БД?
Неконкретный вопрос, на который можно дать только неконкретный ответ: хочу записывать и считывать персистентные пользовательские данные.
E>И обмены с БД идут объектами trx_info_t. Вот trx_info_t я и называю объектом.
Есть как минимум 2 варианта того, что может быть объектом
1) Базовый набор атрибутов, образующих кластерный индекс в файле БД
2) Кортеж, состав атрибутов которого описан в запросе.
Ты о каком из них? Неужели так сложно отойти от заезженой схемы O/R мепперов и взглянуть на ситуацию хоть немножечко пошире?
AVK>>Вот и плохо что нет. Пойми простую вещь — на диск все равно меньше 512 байти не запишешь, даже если тебе всего 8 байт ссылки надо поправить. Соответственно править ссылки в 3 страницах будет медленнее, нежели перезаписать содержимое одной единственной. А таблица пересчета, спасая от правки ссылок в страницах, привносит свои проблемы.
E>Это я понимаю. Но таблица пересчета кроме проблем дает и преимущества. Например, с ее помощью избавляешься от проблемы фрагментации БД.
Не избавляюсь, а лишь замазываю проблему. Я могу убрать фрагментацию логическую (что, вобщем то, не особенно и нужно, потому что 64 бит хватит выше крыши), а вот физическую фрагментацию я так не исправлю.
E>но по сравнению со скоростями дисковой подсистемы...
Ты еще не забыл, что твою таблицу надо грузить целиком в память, а при коммите транзакции немедленно скидывать изменившуюся часть на диск?
AVK>>Пусть страница 8К. Размер БД 10Г. Итого размер таблицы пересчета = 10Г / 8К * 16 = 20М. Считаешь 20 мег это немного?
E>Почему на 16 умножается?
Потому что размер записи таблицы 16 байт — 8 байт логический номер и 8 байт физический адрес. Но даже если брать по 4 байта, все равно 10М это весьма и весьма немало.
E>И это при том, что всю таблицу пересчета в ОП можно не хранить, а подгружать сегменами по мере надобности.
И тут мы попадаем на лишнее обращение к диску (причем с длинным сиком) с катастрофическим падением производительности.
AVK>>Плохо смотришь. Сбой в таблице пересчета абсолютно критичен. Следовательно, внося эту таблицу, мы снижаем надежность системы в целом на вероятность сбоя в таблице пересчета.
E>Надежность фиксации таблицы пересчета конечно же важна. Но подумай сам, неужели надежность фиксации WAL должна быть ниже?
Там структуры проще и примитивнее и запись последовательная. Опять же сбой в WAL всего лишь приведет к неоткату транзакции (или неверному откату). Неприятно, но не смертельно. Главное, что физическая структура БД не испортится. А вот сбой в таблице пересчета это уже капец всей базе.
Здравствуйте, Sinclair, Вы писали:
S>Рекомендую почитать в SQL BOL про организацию файлов MDF. Там все довольно внятно расписано. Не думаю, что стоит изобретать какой-то более хитрый велосипед; разве что покрутить стратегии компактификации БД. В остальном изменения в Yukon сделаны в нужную сторону. К примеру, varchar(max) и varbinary(max) — это просто the must для этой потенциальной встраиваемой БД. Потому что не стоит парить разработчика выбором длины поля типа string и вопросами перехода на Memo. Должны храниться просто System.String, и работать соответственно — быстро для коротких строк, помедленнее для больших. Вот и все чудеса в решете. А то каждый раз думать, сколько места отводить под имя/фамиилию, приклеивать валидаторы к UI...
Интересно, а каким боком все это относится к моему сообщению?
К слову, моя система хранения как раз и создавалась для того, чтобы хранить объекты, динамически изменяющие свой размер (вроде std::string, std::vector, std::list и пр.).
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
AVK>Есть как минимум 2 варианта того, что может быть объектом AVK>1) Базовый набор атрибутов, образующих кластерный индекс в файле БД AVK>2) Кортеж, состав атрибутов которого описан в запросе.
Стало быть я говорю о кортеже.
AVK>Неужели так сложно отойти от заезженой схемы O/R мепперов и взглянуть на ситуацию хоть немножечко пошире?
Ты будешь смеяться, но я только один раз работал с O/R мапперами (в RubyOnRails). А все остальное время с точки зрения разработчика очень примитивной ООБД
AVK>Не избавляюсь, а лишь замазываю проблему. Я могу убрать фрагментацию логическую (что, вобщем то, не особенно и нужно, потому что 64 бит хватит выше крыши), а вот физическую фрагментацию я так не исправлю.
Исправишь. Представь, что во время сохранения в БД твой кортеж оказался размазанным по нескольким разрозненным страницам хранилища. Все. Если ты его будешь обновлять только по этому месту, то он у тебя навсегда останется фрагментированным. Если при каждом обновлении ты будешь его перезаписывать в новое место, есть вероятность (имхо, большая), что ты сможещь записывать его последовательно.
AVK>Ты еще не забыл, что твою таблицу надо грузить целиком в память, а при коммите транзакции немедленно скидывать изменившуюся часть на диск?
Я думаю, что не нужно. Таблица может точно так же помещаться в кэш и выбрасываться оттуда при не надобности.
E>>И это при том, что всю таблицу пересчета в ОП можно не хранить, а подгружать сегменами по мере надобности.
AVK>И тут мы попадаем на лишнее обращение к диску (причем с длинным сиком) с катастрофическим падением производительности.
Здесь лучше бы опираться на реальные замеры.
E>>Надежность фиксации таблицы пересчета конечно же важна. Но подумай сам, неужели надежность фиксации WAL должна быть ниже?
AVK>Там структуры проще и примитивнее и запись последовательная. Опять же сбой в WAL всего лишь приведет к неоткату транзакции (или неверному откату).
Я говорил о другом. Если ты записал в WAL успешно, выполнил fsync, начал запись в БД. Произошел жесткий сбой. Файл WAL запортился. БД уже была частично изменена. Все, приплыли.
AVK> Неприятно, но не смертельно. Главное, что физическая структура БД не испортится. А вот сбой в таблице пересчета это уже капец всей базе.
Для этого можно использовать две копии таблицы (я об этом уже говорил).
И обновлять можно не всю таблицу в конце транзакции, а только изменившиеся ее части.
Собственно, выбирать-то тебе. Я просто хотел сказать, что такой механизм фиксации транзакций так же возможен.
В моей БД WAL дает очень сильный оверхэд при фиксации транзакций. Я бы хотел от него избавиться, вот только попробовать использовать shadow copy пока нет времени.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Sinclair, Вы писали:
S>Рекомендую почитать в SQL BOL про организацию файлов MDF.
А там это описано?
S>К примеру, varchar(max) и varbinary(max) — это просто the must для этой потенциальной встраиваемой БД. Потому что не стоит парить разработчика выбором длины поля типа string и вопросами перехода на Memo.
Здравствуйте, eao197, Вы писали:
E>Стало быть я говорю о кортеже.
Но тогда о каких ссылках на кортежи может идти речь, если сам кортеж может состоять из данных, размещенных в разных индексах? Например такое происходит если кортеж получен в результате джойна.
AVK>>Неужели так сложно отойти от заезженой схемы O/R мепперов и взглянуть на ситуацию хоть немножечко пошире?
E> E>Ты будешь смеяться, но я только один раз работал с O/R мапперами (в RubyOnRails). А все остальное время с точки зрения разработчика очень примитивной ООБД
Не суть важно. Главное что схема одна и та же. Но она далеко не единственно возможная.
E>Исправишь. Представь, что во время сохранения в БД твой кортеж оказался размазанным по нескольким разрозненным страницам хранилища. Все. Если ты его будешь обновлять только по этому месту, то он у тебя навсегда останется фрагментированным.
Непонимаю. Какой кортеж? Кортеж образуется только на этапе запроса. Это read-only структура. Его нельзя менять.
AVK>>Ты еще не забыл, что твою таблицу надо грузить целиком в память, а при коммите транзакции немедленно скидывать изменившуюся часть на диск?
E>Я думаю, что не нужно.
Нужно в обязательном порядке, иначе вылет приложения порушит БД.
E> Таблица может точно так же помещаться в кэш и выбрасываться оттуда при не надобности.
Писать надо сразу, иначе проблем будет слишком много. И непонятно зачем тогда транзакции, если даже после коммита их содержимое может быть потеряно.
E>Я говорил о другом. Если ты записал в WAL успешно, выполнил fsync, начал запись в БД. Произошел жесткий сбой. Файл WAL запортился. БД уже была частично изменена. Все, приплыли.
И я об этом. Не приплыли, потому что физическая структура повреждена не будет, повредится только логическая структура, если в транзакции были согласованные изменения. Это значительно менее страшно.
E>Для этого можно использовать две копии таблицы (я об этом уже говорил).
Это называется положить грабли, а потом строить сверху мост.
E>Собственно, выбирать-то тебе.
Ну почему обязательно мне . Я пока что обсуждаю что тут вобще можно сделать существенно лучше, чем существующие решения. Правда, если когда нибудь дело дойдет до реализации, вряд ли тебе будет интересна реализация под .NET.
E> Я просто хотел сказать, что такой механизм фиксации транзакций так же возможен.
Иван тебе уже объяснил, почему смысла в нем особого нет. Если уж отказываться от WAL, то я бы подумал в сторону Redo Only лога.
Здравствуйте, AndrewVK, Вы писали:
AVK>Но тогда о каких ссылках на кортежи может идти речь, если сам кортеж может состоять из данных, размещенных в разных индексах? Например такое происходит если кортеж получен в результате джойна.
Про ссылки на кортежи я не говорил. Я говорил про ссылки между страницами B+ дерева в индексе. Их можно было бы делать через лишний уровень косвенности. Ну да эту тему мы уже обсудили, судя по всему
E>>Исправишь. Представь, что во время сохранения в БД твой кортеж оказался размазанным по нескольким разрозненным страницам хранилища. Все. Если ты его будешь обновлять только по этому месту, то он у тебя навсегда останется фрагментированным.
AVK>Непонимаю. Какой кортеж? Кортеж образуется только на этапе запроса. Это read-only структура. Его нельзя менять.
Но ведь кортеж из чего-то будет подниматься. Значит прежде select-а, ты должен будешь сделать insert. В insert-е же у тебя все равно будет какой-то кортеж. Не факт, что он у тебя будет в одну страницу помещаться (особенно с учетом varchar переменного размера).
AVK>>>Ты еще не забыл, что твою таблицу надо грузить целиком в память, а при коммите транзакции немедленно скидывать изменившуюся часть на диск?
E>>Я думаю, что не нужно.
AVK>Нужно в обязательном порядке, иначе вылет приложения порушит БД.
Я говорил о том, что не нужно всю таблицу в память загружать.
AVK>И я об этом. Не приплыли, потому что физическая структура повреждена не будет, повредится только логическая структура, если в транзакции были согласованные изменения. Это значительно менее страшно.
Не понимаю. На странице у тебя будет управляющая информация обязательно. Какие-то метки полей, размерности и пр. Если они запортятся, то считай, что и физическая структура баз полетит.
E>> Я просто хотел сказать, что такой механизм фиксации транзакций так же возможен.
AVK>Иван тебе уже объяснил, почему смысла в нем особого нет. Если уж отказываться от WAL, то я бы подумал в сторону Redo Only лога.
Ну здесь есть разные мнения. Константин Книжник не зря в своих БД shadow copy использует. А он очень обстоятельно, насколько я заметил, к разработке подходит.
А Redo Only лог позволит транзакции откатывать?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали: AVK>Тут только надо помнить насколько это реализуемона практике.
Прекрасно реализуемо. Примеров тому довольно много AVK>>>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль? S>>А можно попонятнее?
AVK>А что конкретно непонятно?
Что такое декларативный sql-like синтаксис я понимаю. А вот что такое "функциональный стиль" — не очень. Ты имеешь в виду линqовские лямбды/анонимные методы? AVK>>>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД? S>>Имеется в виду отказ от byte[]?
AVK>Имеется ввиду произвольный формат строки без наличия соответствующего кортежа, описанного в терминах CLR.
А, вот это как раз возможно и допустимо. Проекции можно делать и игнорированием лишних полей (т.к. у нас нет узкого места — сети для перекачки лишнего трафика между клиентом и сервером); джойны, наверное, можно делать и в виде доп.навигации (коли захочется). В общем, не уверен. AVK>Почему?
Это я про byte[]. Просто потому, что есть масса данных, которые иначе как в виде byte[] особо и не представишь. К тому же если есть охота хранить всякие пользовательские типы, то это 100% будет сделано через сериализацию и именно в byte[] переменной длины, т.к. в фиксировнную байт-раскладку умеют превращаться только структы.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
AVK>>Непонимаю. Какой кортеж? Кортеж образуется только на этапе запроса. Это read-only структура. Его нельзя менять.
E>Но ведь кортеж из чего-то будет подниматься. Значит прежде select-а, ты должен будешь сделать insert. В insert-е же у тебя все равно будет какой-то кортеж.
Нет, вот в insert я должен использовать то, что я упоминал под п.1.
E> Не факт, что он у тебя будет в одну страницу помещаться (особенно с учетом varchar переменного размера).
В классических БД он обязан помещаться на одну страницу. Даже с учетом varchar. Единственное исключение это varcharmax и varbinarymax в последнем сиквеле.
AVK>>Нужно в обязательном порядке, иначе вылет приложения порушит БД.
E>Я говорил о том, что не нужно всю таблицу в память загружать.
Насчет лишней записи на диск возражений нет?
E>Не понимаю. На странице у тебя будет управляющая информация обязательно. Какие-то метки полей, размерности и пр. Если они запортятся, то считай, что и физическая структура баз полетит.
В логе не пишется изменение физической разметки, в логе пишутся только логические операции. Если в момент записи порушится именно физическая структура БД (в единичном обращении к диску), то вне зависимости от схемы БД придет пипец. Я же говорю о другом — когда просто транзакция не успела закоммититься при сбое, например приложение вылетело на полпути при коммите.
Здравствуйте, Sinclair, Вы писали:
AVK>>Тут только надо помнить насколько это реализуемона практике. S>Прекрасно реализуемо. Примеров тому довольно много
Какие то все примеры с бюджетами в сотни мегабаксов
AVK>>А что конкретно непонятно? S>Что такое декларативный sql-like синтаксис я понимаю. А вот что такое "функциональный стиль" — не очень. Ты имеешь в виду линqовские лямбды/анонимные методы?
Как один из вариантов да. Точнее в LINQ есть и та и другая форма записи.
AVK>>Имеется ввиду произвольный формат строки без наличия соответствующего кортежа, описанного в терминах CLR. S>А, вот это как раз возможно и допустимо. Проекции можно делать и игнорированием лишних полей (т.к. у нас нет узкого места — сети для перекачки лишнего трафика между клиентом и сервером);
Проблема не в трафике, проблема в контроле типов. Хотелось бы, если в запросе часть полей не используется, чтобы уже компилятор поймал за руку при попытке их использовать.
AVK>>Почему? S>Это я про byte[]. Просто потому, что есть масса данных, которые иначе как в виде byte[] особо и не представишь. К тому же если есть охота хранить всякие пользовательские типы, то это 100% будет сделано через сериализацию и именно в byte[] переменной длины, т.к. в фиксировнную байт-раскладку умеют превращаться только структы.
Ну так зачем тогда в этом случае byte[], если есть соотв. тип? Но на самом деле я спрашивал про другое — возможно ли полностью отказаться от типов и динамических кортежей БД в пользу статической типизации?
Здравствуйте, AndrewVK, Вы писали:
AVK>Нет, вот в insert я должен использовать то, что я упоминал под п.1.
Да на самом деле, на низком уровне БД это не суть важно. Важно, что есть некоторая порция данных, которую нужно записать.
AVK>В классических БД он обязан помещаться на одну страницу. Даже с учетом varchar. Единственное исключение это varcharmax и varbinarymax в последнем сиквеле.
Так ведь мы не про классическую БД до сих пор разговаливали
E>>Я говорил о том, что не нужно всю таблицу в память загружать.
AVK>Насчет лишней записи на диск возражений нет?
Я правда не знаю, откуда берется лишняя запись
Но из-за того, что shadow copy я сам не реализовывал, то настаивать не буду. Наверняка в реальной жизни все будет не так гладко.
AVK>В логе не пишется изменение физической разметки, в логе пишутся только логические операции. Если в момент записи порушится именно физическая структура БД (в единичном обращении к диску), то вне зависимости от схемы БД придет пипец. Я же говорю о другом — когда просто транзакция не успела закоммититься при сбое, например приложение вылетело на полпути при коммите.
Ок. Понял в чем была причина недопонимания. Чуть-чуть лирического отступления, извини за многословность. Так вот, в ООБД различаются сервера объектов и сервера страниц. Сервер объектов при обращении к объекту манипулирует только объектами, абстрагируясь от их размещения на страницах БД. Соответственно, в лог записываются только значения объектов. Поэтому в логе есть только логическая информация. Сервера страниц при обращении к объекту возвращают все страницы, которые содержат данный объект. Соответственно, при изменении объекта назад приходят опять страницы и эти страницы сохраняются в логе. Поэтому в таком подходе в логе есть и информация о физической структуре БД. И падение такого лога -- это очень неприятная ситуация.
То о чем говорил ты, похоже, можно сравнить с поведением серверов объектов.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, GlebZ, Вы писали:
GZ>Только это сильно усложнит систему хранения и операций с ним. Да и статистику, если будешь делать, также.
Да нет, не сильно... Это сильно усложняет всяческие навороенные оптимизации тепа Read Ahead-а и прочей лабуды, но для настольных БД это не нужно... А для простых вещей достаточно аккуратно реализовать работу со страницами данных, чтобы они имели возможность ссылаться друг на друга...
Здравствуйте, Merle, Вы писали:
M>У Shadow Copy свои тараканы, например там минимальная гранулярность — страница, если я правильно помню... Хотя для настольных СУБД это может быть и не проблема. С частичным откатом там тоже проблема, если вдруг Save Point-ы понядобятся или, упаси байт, вложенные транзакции..
Да где же своих тараканов нет
M>Конечно.. Собственно WAL и Redo Only вовсе не взаимоисключающие понятия. Redo Only — это способ организаци лога WAL — способ работы с логом, означающий что преже чем попасть в основную базу данные обязательно должны оказаться в логе, что гарантирует восстановимость. M>Соответственно, при Redo Only логе данные в базу до коммита никогда не попадут и для отката можно просто зачитать предыдущие данные из БД. M>При коммите надо будет сбросить все данные в основное хранилище, если используется схема без check-поинтов, или сбросить на диск в лог и перенести в основное хранилище по чек-поинту.
Опаньки, оказывается, я использую у себя Redo Only лог
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Merle, Вы писали:
M>Есть так же схема No Redo/No Undo, по сути это Redo Only, но все Redo данные держатся в памяти, а при коммите атомарно сбрасываются на диск в основное хранилище, главная проблема — обеспечить эту атомарность..
ИМХО вероятностью сбоя в момент записи в случае сабжа можно пренебречь. Главное чтобы от программных ошибок БД не портилась.
M> Ну и что делать если память закончилась.....
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, GlebZ, Вы писали:
GZ>>Только это сильно усложнит систему хранения и операций с ним. Да и статистику, если будешь делать, также. M>Да нет, не сильно... Это сильно усложняет всяческие навороенные оптимизации тепа Read Ahead-а и прочей лабуды, но для настольных БД это не нужно... А для простых вещей достаточно аккуратно реализовать работу со страницами данных, чтобы они имели возможность ссылаться друг на друга...
То бишь взять Oracle политику? Хотя они поддерживают строки на несколько страниц, строки все равно ограничены.
Попробуй подумать как сделать на varchar(max) B+ индекс?
Здравствуйте, GlebZ, Вы писали:
GZ>То бишь взять Oracle политику?
Причем здесь Oracle? MS поступает точно так же, да и DB2 AFAIK...
GZ> Хотя они поддерживают строки на несколько страниц, строки все равно ограничены.
Ну да 2ГБ, если брать вариант MS...
GZ>Попробуй подумать как сделать на varchar(max) B+ индекс?
А зачем? В том же сиквеле длинна ключа ограничена 900-та байтами и ничего фатального в этом ограничении я не вижу.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, GlebZ, Вы писали:
GZ>>То бишь взять Oracle политику? M>Причем здесь Oracle? MS поступает точно так же, да и DB2 AFAIK...
Для MSSQL varchar(max) image e.t.c. лежат в отдельных сегментах. Oracle умеет запись класть на несколько страниц. Разница есть.
GZ>>Попробуй подумать как сделать на varchar(max) B+ индекс? M>А зачем? В том же сиквеле длинна ключа ограничена 900-та байтами и ничего фатального в этом ограничении я не вижу.
Как результат, у нас нет уверености что мы сможем проиндексировать строки с неограниченной переменной длиной(как предлагал Sinclair).
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, GlebZ, Вы писали:
AVK>>>Тока с сабжем это немного общего имеет. GZ>>Ну вот. Ограничиваем применимость сабжа? AVK>Да, конечно. Невозможно сождать эффективную, простую и универсальную БД одновременно.
Зато можно к этому стремиться.
AVK>Если бы их не было вовсе ничего бы принципиально не изменилось, функциональная форма совсем не хуже.
Насчет функциональной формы подумай. Для меня частой задачей является задача сборки SQL запроса к БД(я работаю с сущностями которые могут изменяться в runtime). Что будет в случае функциональной формы?
AVK>Читайте доки, они рулез.
Ладно, тебя не переубедишь. Закончим пока данную тему.
GZ>>Зачем keyset? Зачем курсоры? Мы можем дать пользователю единую феню и не мучить его не особо нужным функционалом. AVK>Затем что причины, почему ООБД до сих пор не получили распространения всем хорошо известны.
Отнюдь не в keyset. И лежат проблемы совершенно в другой плоскости. Проблему которую я описал показывает что все прекрасно решается как в функциональной форме(с делегатом) без возврата результата, так и через ienumerator взятый из List. Пользователь сам может решить и определить какой путь ему важен. Курсор как таковой мало интересен и малофункицонален и неудобен по сравнению с тем же IEnumerator.
Насчет ключей есть другая думка. В реляционных базах данных есть несколько типов join. Один из них построен на хеше. То есть, у нас есть два отношения. Один из них меньше другого. При join, база данных строит хеш-таблицу RID по маленькому списку, и затем просто находит значения для большого списка и соединяет. Очень действенный механизм. Поскольку уже никто не возражает что ключ должен быть глобально уникальным для БД, и синтетическим, то вполне можно использовать именно хеширование. Кроме того, это даст нам путь быстрого нахождение одного объекта.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Max404.NET, Вы писали:
MN>>а чем msde(2005express) не устраивает? M>
M>однако по прежнему есть ряд применений, для которых их навороты не нужны, равно как не нужен оверхед, связанный с многопользовательским доступом и сложное администрирование
Для начала вычеркиваем фразу про сложное администрирование (2005 express).
Потом задумываемся про размеры оверхеда и его реальный вклад.
Потом вспоминаем про удобство единообразного подхода к работе с хранилищами данных.
Я лично пришел к выводу, что мне такая штука не нужна даже даром — потому как я буду сомневаться в стабильности ее работы и все равно выберу sql.
А вообще, такие вещи вроде давно уже есть, только мало кто их использует.
Здравствуйте, eao197, Вы писали:
E> Так вот, в ООБД различаются сервера объектов и сервера страниц. Сервер объектов при обращении к объекту манипулирует только объектами, абстрагируясь от их размещения на страницах БД. Соответственно, в лог записываются только значения объектов. Поэтому в логе есть только логическая информация.
Так работает WAL, да и в принципе логгирование. Собственно, в том числе, об эффективности такого подхода и не обязательности хранения физической структуры, и рассказывал Мохан в своем докладе про ARIES.
E> Сервера страниц при обращении к объекту возвращают все страницы, которые содержат данный объект. Соответственно, при изменении объекта назад приходят опять страницы и эти страницы сохраняются в логе. Поэтому в таком подходе в логе есть и информация о физической структуре БД. И падение такого лога -- это очень неприятная ситуация.
А вот так работает Shadow Copy...
Здравствуйте, eao197, Вы писали:
AVK>>В классических БД он обязан помещаться на одну страницу. Даже с учетом varchar. Единственное исключение это varcharmax и varbinarymax в последнем сиквеле.
E>Так ведь мы не про классическую БД до сих пор разговаливали
Ну а коль так, тогда ты прежде должен описать зачем нам расцеплять строку на несколько страниц и насколько часто это будет происходить.
Здравствуйте, AndrewVK, Вы писали:
AVK>Ну а коль так, тогда ты прежде должен описать зачем нам расцеплять строку на несколько страниц и насколько часто это будет происходить.
Представим, что ты хочешь сохранить в своей настольной БД письмо. В виде чего ты его будешь сохранять?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, GlebZ, Вы писали:
AVK>>Да, конечно. Невозможно сождать эффективную, простую и универсальную БД одновременно. GZ>Зато можно к этому стремиться.
Можно. Но среднюю точку все равно придется выбирать.
AVK>>Если бы их не было вовсе ничего бы принципиально не изменилось, функциональная форма совсем не хуже. GZ>Насчет функциональной формы подумай. Для меня частой задачей является задача сборки SQL запроса к БД(я работаю с сущностями которые могут изменяться в runtime). Что будет в случае функциональной формы?
То же самое. Никакой разницы нет. Процедура перехода от декларативной формы к функциональной, по крайней мере для LINQ, проста как 3 копейки.
AVK>>Затем что причины, почему ООБД до сих пор не получили распространения всем хорошо известны. GZ>Отнюдь не в keyset.
А я это и не говорил.
GZ> И лежат проблемы совершенно в другой плоскости.
А это пофигу. Прежде чем обсуждать аспекты ООБД, сначала надо обсудить необходимость в ООБД. Лично я пока более оптимальным выбором для сабжа считаю реляционный движек.
GZ> Проблему которую я описал показывает что все прекрасно решается как в функциональной форме(с делегатом) без возврата результата, так и через ienumerator взятый из List. Пользователь сам может решить и определить какой путь ему важен. Курсор как таковой мало интересен и малофункицонален и неудобен по сравнению с тем же IEnumerator.
IEnumerator это и есть курсор. Соответственно типизированный курсор, который предлагается, это IEnumerator<T>. Что касается ООБД, то вне наличия возможности хранения и индексирования составных типов данных с точки зрения дизайна лучше сделать меппер, нежели прошивать это в БД.
GZ>Насчет ключей есть другая думка. В реляционных базах данных есть несколько типов join. Один из них построен на хеше.
На хеше построен не join, а одна из его реализаций.
GZ> То есть, у нас есть два отношения. Один из них меньше другого. При join, база данных строит хеш-таблицу RID по маленькому списку, и затем просто находит значения для большого списка и соединяет.
Ага.
GZ> Очень действенный механизм. Поскольку уже никто не возражает что ключ должен быть глобально уникальным для БД, и синтетическим, то вполне можно использовать именно хеширование.
Хеш джойн? Ну да, его и сиквел в основном использует.
GZ> Кроме того, это даст нам путь быстрого нахождение одного объекта.
Тут не понял. При чем тут join и поиск в B+? Или ты предлагаешь хеш-индексы? Не думаю что это хорошая идея, даже в условиях PK фиксированного типа.
Здравствуйте, AndrewVK, Вы писали:
E>>Представим, что ты хочешь сохранить в своей настольной БД письмо. В виде чего ты его будешь сохранять?
AVK>varcharmax
Ну вот, имхо, ты сам и ответил на свой вопрос
Аналогичными примерами могут быть текстовые документы, которые хранятся в БД как последовательность параграфов (отдельный параграф как отдельный varchar).
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, AndrewVK, Вы писали:
AVK>Можно. Но среднюю точку все равно придется выбирать.
+1
AVK>>>Если бы их не было вовсе ничего бы принципиально не изменилось, функциональная форма совсем не хуже. GZ>>Насчет функциональной формы подумай. Для меня частой задачей является задача сборки SQL запроса к БД(я работаю с сущностями которые могут изменяться в runtime). Что будет в случае функциональной формы?
AVK>То же самое. Никакой разницы нет. Процедура перехода от декларативной формы к функциональной, по крайней мере для LINQ, проста как 3 копейки.
Не-а. Ты не о том. Там редактирование различных запросов происходят по интересной схеме. Что то типа:
var v=from c in db.bla select c;
var v1=from c1 in db.bla1, c2 in v where c1.id=c2.id select c2;
var res=v1.ToList();
У меня есть сомнения в оптимальности такого подхода. Или надо будет писать логический оптимизатор запросов.
AVK>А это пофигу. Прежде чем обсуждать аспекты ООБД, сначала надо обсудить необходимость в ООБД. Лично я пока более оптимальным выбором для сабжа считаю реляционный движек.
Если ты где нибудь найдешь у меня упоминание о том что я предлагаю OOБД, я буду благодарен. Я только скромно спросил а будет ли наследование, и пока тему OODB вообще закрыл.
GZ>> Проблему которую я описал показывает что все прекрасно решается как в функциональной форме(с делегатом) без возврата результата, так и через ienumerator взятый из List. Пользователь сам может решить и определить какой путь ему важен. Курсор как таковой мало интересен и малофункицонален и неудобен по сравнению с тем же IEnumerator.
AVK>IEnumerator это и есть курсор. Соответственно типизированный курсор, который предлагается, это IEnumerator<T>. Что касается ООБД, то вне наличия возможности хранения и индексирования составных типов данных с точки зрения дизайна лучше сделать меппер, нежели прошивать это в БД.
a)Логика выполнения запроса в режиме на каждый row — достаточно сложна. При использовании проекций, каждый раз нам придется его выполнять сново, или удерживать результаты части запроса.
б) Или в запросе используются данные, получая key без данных, мы должны перечитывать их сново.
Моя аргументация понятна?
Вопрос:
Примерная структура:
1 уровень. Файл, сегменты, страницы.
2 уровень. Типизированные данные, то бишь таблицы или отношения (должны иметь информацию о типах), индексы.
3 уровень. Собственно он и есть конечная цель. Объекты и типизированные списки объектов(или tuples, по фиг). То есть то, чем пользуется пользователь.(должна иметь свою информацию о типах).
Я правильно тебя понял?
GZ>>Насчет ключей есть другая думка. В реляционных базах данных есть несколько типов join. Один из них построен на хеше. AVK>На хеше построен не join, а одна из его реализаций.
Я этого и не скрывал
GZ>> Кроме того, это даст нам путь быстрого нахождение одного объекта. AVK>Тут не понял. При чем тут join и поиск в B+? Или ты предлагаешь хеш-индексы? Не думаю что это хорошая идея, даже в условиях PK фиксированного типа.
Вот как раз в случае PK фиксированного типа, и хорошая идея. Одно время над этим бились все реляционщики, пытались построить hash эффективный для всех данных(проклиная SQL). Поскольку у нас фиксированный тип, у нас нет никаких противопоказаний. Сортировка по синтетическому ключу не нужна как таковая. SelectByKey — со сложностью O(1) будет не слишком отставать от SelectList(если они в кэше). А также мы сразу решим проблему быстрого join.
Здравствуйте, Merle, Вы писали:
GZ>>Как результат, у нас нет уверености что мы сможем проиндексировать строки с неограниченной переменной длиной(как предлагал Sinclair). M>Во-первых Тоха не предлагал индексировать строки с различной переменной длинной, он предлагал их хранить и не париться над размером. Во-вторых я не вижу почему бы не индексировать только первый килобайт, если строка слишком большая, все равно ключ текст из середины сравнивать не умеет, и сравнение таких больших кусков очень большая экзотика...
Очень нехорошее решение тогда будет. Реализуешь решение, проходит год, и какой-то, обязательно наиболее важный клиент, начинает бочки гнать. Уже попадал на такое. Лучше уж сложнее, но чтобы потом исправить легко было, или сразу принять другое нормальное решение по реализации.
Здравствуйте, Merle, Вы писали:
GZ>>Для MSSQL varchar(max) image e.t.c. лежат в отдельных сегментах. Oracle умеет запись класть на несколько страниц. Разница есть. M>MSSQL тоже умеет, так что разницы нет. Это он специально для max-типов отдельное хранилище держит, что вообщем разумно и совершенно не мешает сделать так же. А вот если сумма обычных varchar-ов вылезает за размер страницы, то он совершенно спокойно резервирует дополнительную страницу под это дело и кладет хвостик туда, проставляя ссылочку.
Это 2005? Наконец-то.
Здравствуйте, GlebZ, Вы писали:
GZ>>>Насчет функциональной формы подумай. Для меня частой задачей является задача сборки SQL запроса к БД(я работаю с сущностями которые могут изменяться в runtime). Что будет в случае функциональной формы?
AVK>>То же самое. Никакой разницы нет. Процедура перехода от декларативной формы к функциональной, по крайней мере для LINQ, проста как 3 копейки. GZ>Не-а. Ты не о том. Там редактирование различных запросов происходят по интересной схеме. Что то типа: GZ>
GZ>var v=from c in db.bla select c;
GZ>var v1=from c1 in db.bla1, c2 in v where c1.id=c2.id select c2;
GZ>var res=v1.ToList();
GZ>
GZ>У меня есть сомнения в оптимальности такого подхода. Или надо будет писать логический оптимизатор запросов.
И при чем здесь функциональная форма? Ты декларативную привел.
GZ>a)Логика выполнения запроса в режиме на каждый row — достаточно сложна. При использовании проекций, каждый раз нам придется его выполнять сново, или удерживать результаты части запроса. GZ>б) Или в запросе используются данные, получая key без данных, мы должны перечитывать их сново. GZ>Моя аргументация понятна?
Неа. Я уже совершенно потерялся и не могу понять, что ты хочешь доказать.
GZ>Вопрос: GZ>Примерная структура: GZ>1 уровень. Файл, сегменты, страницы. GZ>2 уровень. Типизированные данные, то бишь таблицы или отношения (должны иметь информацию о типах), индексы. GZ>3 уровень. Собственно он и есть конечная цель. Объекты и типизированные списки объектов(или tuples, по фиг). То есть то, чем пользуется пользователь.(должна иметь свою информацию о типах). GZ>Я правильно тебя понял?
Примерно.
AVK>>На хеше построен не join, а одна из его реализаций. GZ>Я этого и не скрывал
Я просто уточняю чтобы не было недопонимания.
AVK>>Тут не понял. При чем тут join и поиск в B+? Или ты предлагаешь хеш-индексы? Не думаю что это хорошая идея, даже в условиях PK фиксированного типа. GZ>Вот как раз в случае PK фиксированного типа, и хорошая идея. Одно время над этим бились все реляционщики, пытались построить hash эффективный для всех данных(проклиная SQL).
Не, проблема с хеш-индексом не в этом, а в том, что при модификации такого индекса он ведет себя не очень хорошо для того чтобы хранить его на диске. Иы можешь предложить алгоритм, чтобы количество дисковых операций при добавлении и удалении значений было сопоставимым с В+ индексом?
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>> Ничто не мешает сделать многопользовательский доступ, но на уровнем удаленных методов. В большинстве случаев этого достаточно.
AVK>Знаешь, я на эту тему с тобой спорить не буду, потому как бесполезно. Можешь делать. Когда сделаешь, тогда и поговорим. А пока что мой опыт свидетельствует, что твои слова далеки от реальности.
Я считаю, что многопользовательский доступ только и всего. AVK>>>Т.е. данные внутри БД описываются системой типов самой БД, а прикладной код должен самостоятельно выполнять конверсию? И что мы выигрываем при этом?
S>> ООП подход.
AVK>??? Это конверсия типов то ООП?
Не совсем конверсия это раз, второе это неограниченность типа. У тебя есть кусок памяти в корый ты пихаешь, что угодно
S>> БД нужно только знание IComparer для индексов и длина записи. В большинстве случаев поля будут иметь неопределенный тип итд.
AVK>Ерунда. Поле в БД не может иметь неопределенный тип, хотя бы потому что на тип завязано построение В+ дерева.
Нужно только длинаключа и (смещения и длины полей для форирования ключа в индексе) длина записи.
Так или иначе нужна БД над которой легко делать ООП надстройку.
S>> Я смотрю на такую БД с точки зреня 1С, Паруса , акзапты.
AVK>А теперь погляди на заголовок темы.
Сделав БД тебе захочется от неё большего. Во всяком случае DBase вроде как развиваются.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
AVK>>Ерунда. Поле в БД не может иметь неопределенный тип, хотя бы потому что на тип завязано построение В+ дерева. S> Нужно только длинаключа и (смещения и длины полей для форирования ключа в индексе) длина записи.
Ага. А еще нужен хеш-код.
AVK>>А теперь погляди на заголовок темы. S> Сделав БД тебе захочется от неё большего.
Здравствуйте, mrozov, Вы писали:
M> Но при чем тут сложности с администрированием???
При том что в одних задачах можно обойтись без администрирования, а в других нет.
M> Или ты еще просто не использовал эту штуку?
M>Боюсь, что "приходится изобретать что-то свое" прямо противоречит самому смыслу топика.
Это каким образом?
M>Ежели мы думаем над универсальностью, то нужна серьезная теоретическая база.
Теоретическая база нужна всегда, вне зависимости от универсальности.
M>На коленках это делать бесполезно. Труд огромный, а выигрыш -ну....
Здравствуйте, GlebZ, Вы писали:
GZ>Очень нехорошее решение тогда будет.
Ничего нехорошего в нем нет.
GZ> Реализуешь решение, проходит год, и какой-то, обязательно наиболее важный клиент, начинает бочки гнать.
На что?
GZ>Лучше уж сложнее, но чтобы потом исправить легко было, или сразу принять другое нормальное решение по реализации.
Это и есть нормальное решение, здесь не надо сложнее. Для поиска по таким текстам B+ все равно бесполезен, здесь надо все равно движек поиска по блобам отдельно подключать. А ключа размером с килобайт для B+ — за глаза.
Здравствуйте, eao197, Вы писали: E>Интересно, а каким боком все это относится к моему сообщению?
Таким, что не надо сидеть и гадать, что дешевле — таблицы пересчета или там что еще. Ты все же сходи, почитай, как дяди делают. Твои рассуждения про замедление a[t[i]] по срввнению с a[i] — извини, лепет. Андрей говорит о том, что для выборки данных в твоем варианте надо сделать два обращения к диску — одно для t[i], и второе для a[t[i]]. E>К слову, моя система хранения как раз и создавалась для того, чтобы хранить объекты, динамически изменяющие свой размер (вроде std::string, std::vector, std::list и пр.).
Я мало знаю про твою систему хранения, зато знаю, что у Юкона мажорный номер версии равен 9. Эти парни уже пятнадцать лет полируют глюкало, основываясь на очень подробных данных о фактическом использовании, передовых теоретических разработках, и глубоких знаниях нижележащих технологий. Я слежу за эволюцией их стораджа начиная с версии 6.5. И я очень сомневаюсь, что кустарные поделки смогут сильно их превзойти на аналогичном поле.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AndrewVK, Вы писали: AVK>Ну так зачем тогда в этом случае byte[], если есть соотв. тип? Но на самом деле я спрашивал про другое — возможно ли полностью отказаться от типов и динамических кортежей БД в пользу статической типизации?
Боюсь, что нет. Давай попробуем выполнить типичный запрос. Пусть это будет почтовая программа — ок, выведем список фолдеров по убыванию суммарного размера непрочитанных сообщений.
На SQL это что-то типа
select folder.*, u.unreadSize
from folder inner join
(select folderId, sum(size) as unreadSize from message where read=0 group by folderId) u on u.folderId = folder.id
Что мы видим? Мы добавили к кортежу folder вычисляемое поле. Причем воспользовались джойном и агрегатом. Можно было, конечно, вставить в кортеж настоящее поле и обновлять его — денормализовать базу. Но денормализаций на все случаи жизни не напасешься.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, GlebZ, Вы писали:
AVK>>И при чем здесь функциональная форма? Ты декларативную привел. GZ>Перепиши в функциональных терминах, будет то же самое. Проблема существует.
Может быть. Но какое это имеет отношение к функциональному стилю?
AVK>>Неа. Я уже совершенно потерялся и не могу понять, что ты хочешь доказать. GZ>Что keyset не нужен.
В ООБД? Возможно. А вот в реляционных иногда очень даже.
AVK>>Примерно. GZ>Отлично, сразу уточняющий вопрос: GZ>При трансформации из записей таблиц в объекты с помощью операции проекции мы теряем информацию о том как этот объект живет на втором уровне. Как эту проблему решать?
А вот именно этот вопрос я и задавал. Ответов я знаю несколько. Можно анализировать IL, можно отказаться от лямбд в операции проекции, можно использовать LINQ.
GZ>Легко. Но надо сначало со структурой хранения. Хеш функция ведь должна по чему-то адресоваться.
Здравствуйте, Sinclair, Вы писали:
S>Что мы видим? Мы добавили к кортежу folder вычисляемое поле.
Ты забыл о том, что мы говорим о настольной БД, а не о сервере. В настольной БД делать вычисления движком БД бессмысленно. И, в любом случае, что здесь изменит отсутствие типизации?
Здравствуйте, Sinclair, Вы писали:
S>Опять же упрощается реализация FK; заодно появляется возможность отказаться от произвольных JOIN и заставить джониться только по FK.
Это, имхо, скорее плохо, чем хорошо. Вот удобный синтаксис специально для join'ов по FK — это хорошо. Но ограниение...
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Ерунда. Поле в БД не может иметь неопределенный тип, хотя бы потому что на тип завязано построение В+ дерева. S>> Нужно только длинаключа и (смещения и длины полей для форирования ключа в индексе) длина записи.
AVK>Ага. А еще нужен хеш-код.
Вообще же можно делать БД как некое множество дженерик классов со всеми вытекающими. AVK>>>А теперь погляди на заголовок темы. S>> Сделав БД тебе захочется от неё большего.
AVK>Если захочется большего, я возьму MSSQL.
Она тебе не даст той свободы действий и скорости. А вот БД как абстрактный класс даст возможность применять намного больше фантазии и инструменты для отражения различных классов но такую БД.
Во всяком случае, такой подход для меня лично не является утопией.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Вообще же можно делать БД как некое множество дженерик классов со всеми вытекающими.
No comments.
S>Она тебе не даст той свободы действий и скорости.
Зато даст надежность, масштабируемость и предсказуемость.
S>А вот БД как абстрактный класс даст возможность применять намного больше фантазии и инструменты для отражения различных классов но такую БД.
Ага, а заодно потратить несколько лишних мегабаксов на проект.
S> Во всяком случае, такой подход для меня лично не является утопией.
S>select folder.*, u.unreadSize
S>from folder inner join
S>(select folderId, sum(size) as unreadSize from message where read=0 group by folderId) u on u.folderId = folder.id
S>
S>Что мы видим? Мы добавили к кортежу folder вычисляемое поле. Причем воспользовались джойном и агрегатом. Можно было, конечно, вставить в кортеж настоящее поле и обновлять его — денормализовать базу. Но денормализаций на все случаи жизни не напасешься.
Нас вообще-то должно волновать только "select folder.*, u.unreadSize". Остальное, то что внутри запроса, как я понимаю, дело компилятора запроса. Ну я виже два способа: первый — анонимные типы, второй — явно указанный тип, т.е:
p()
{
foreach (auto i in (select folder.*, u.unreadSize from ...))
{
//...
};
}
struct Row
{
Folder folder;
int unreadSize;
};
p()
{
foreach (auto i in (select new Row(folder, u.unreadSize) from ...))
{
m(i);
};
}
m(Row row) {...}
Имхо, оба способа должны присутствовать. И разве этого будет недостаточно?
Здравствуйте, AndrewVK, Вы писали:
AVK>Когда то давно, когда PC только появлялись, было такое явление как настольные СУБД. Потом их практически вытеснили SQL-сервера, и если они и есть где, то это в основном развитие старых продуктов. AVK>SQL-сервера это конечно здорово, однако по прежнему есть ряд применений, для которых их навороты не нужны, равно как не нужен оверхед, связанный с многопользовательским доступом и сложное администрирование. AVK>Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов. Более конкретный список вопросов: AVK>1) in process или out of process?
Желательны оба варианта. В первом варианте неплохо бы получить "сырой" интерфейс на какие-нить row set-ы, чтобы помимо декларативного SQL иметь возможность для императивных циклических алгоритмов.
AVK>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc
Ты будешь разрабатывать подобное?
В общем, мне нравится подход "больших" баз, типа MS SQL, когда я разные таблицы и даже разные колонки таблиц или части таблиц (индексы) могу распихивать по разным физическим файлам. Очень удобно порой, особенно насчет обсуждавшихся здесь "больших блобов". MS SQL заметно шустрее работает, когда большие колонки-блобы, которые не участвуют в подавляющем большинстве запросов, сидят в отдельном физическом файле (или даже диске).
AVK>3) Описание метаданных
Не понятен вопрос. Речь идет о возможном РАСШИРЕНИИ стандартных метаданных? (стандартные — ну там тип поля и ограничения, типа nullable, участие в индексе или ограничения в виде SQL)
AVK>4) Способ формирования запросов
Если in-proccess, то доп. через "сырые" интерфейсы доступа к данным.
AVK>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
4 и 5 — это продолжение 1. Если in-proccess, то не имеет смысла сильно разграничивать полномочия, все равно хачить будут, лучше дать нормальные отлаженные интерфейсы для непосредственного доступа к данным. Если out-of-proccess, то разумеется, полное разграничение полномочий. Общение — только через запросы. Максимум, через некий аналог SQLDMO.
AVK>6) Алгоримты деплоймента
Не критично. Хотя, желательно, конечно, поддержка как стандартной инсталляхи, так и в виде DLL, для распространения как часть другого продукта.
Здравствуйте, AndrewVK, Вы писали:
AVK>О первичных ключах: AVK>1) Допустимо ли требование обязательного наличия первичного ключа?
+
AVK>2) Допустимо ли требование несоставного первичного ключа?
+
AVK>3) Допустимо ли требование первичного ключа определенного типа?
+
AVK>4) Допустимо ли требование первичного ключа типа GUID?
—
AVK>О расширяемости: AVK>Что должно быть расширяемо в сабже?
AVK>О keysets: AVK>1) Допустимо ли встраивание этой механики в движек БД.
+ AVK>2) Достаточно ли самого простого варианта, или нужна возможность подкрузки в кейсет части данных?
не совсем понятно, какая догрузка имеется в виду? AVK>3) Нужна ли многостадийная загрузка или подгрузка в 2 стадии — кейсет и остальные данные? Или может еще какой вариант?
3-й вариант — загрузка каждого элемента или группы элементов по требованию (это имелось ввиду?).
AVK>О запросах подробнее: AVK>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов?
скорее да, чем нет... ибо удобно, да и опять же, возможно захочется тулзы делать. В принципе, можно SQL прикрутить как внешннюю либу AVK>2) Что лучше — выборки или навигационный способ(курсоры).
Оба хороши, каждый для своего AVK>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль?
будет свой язык???
AVK>О метаданных: AVK>1) Допустим ли отказ от специфичных для БД метаданных в пользу метаданных, встроенных в платформу?
вон оно как... скорее да, чем нет. AVK>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД?
трудный вопрос... А как насчет проекций и отчетов? AVK>3) Должны ли типы хранится в БД вместе с данными?
минимальная схема+аттрибуты — да. Вроде как дублирование с кодом (вопросы выше), с одной стороны. С другой стороны — хоть какая-то защита от несогласованных изменений в коде и базе.
AVK>О деплойменте: AVK>Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек?
Вряд ли это легко без специального инструментария по смене типа. Т.е. мы поменяли имя и тип колонки/поля. Если эти действия не трекить, но непонятно, какая колонка куда поменялась... В общем, если речь идет о дотнет (насколько я понял), то типы и результирующие сборки для подобной БД нужно разрабатывать в некоем своем инструменте, с поддержкой такой реструктуризацией. Скорее, не в движек это надо встраивать, а в инструмент разработки. AVK>Какие еще аспекты БД было бы интересно рассмотреть с точки зрения описанной задачи?
Политики владения/связи. Привязать сюда же GC для зависимых данных (почему бы и нет?)
Здравствуйте, AndrewVK, Вы писали:
AVK>P.S. AVK>О транзакциях: AVK>1) Оптимистичные или пессимистичные? AVK>2) Нужны ли вложенные транзакции? AVK>3) Можно ли обойтись без транзакций вовсе или вынести их из движка БД на уровень библиотеки?
Если делать только пессимистичные (а только они и имеют право называться настоящими ), то можно на уровень либы.
А эмуляцию оптимистичных пускай прикладной код делает на своих кешах.
Здравствуйте, Merle, Вы писали:
AVK>>1) Оптимистичные или пессимистичные? M>А какая разница, если БД однопользовательская?
А почему бе не рассмотреть вариант мини-сервера приложений, где используется такая легковесная БД?
AVK>>2) Нужны ли вложенные транзакции? M>Нет.
Спорно. Особенно, если будет предоставлена возможность императивно обрабатывать данные.
AVK>>3) Можно ли обойтись без транзакций вовсе или вынести их из движка БД на уровень библиотеки? M>Нет, Атомарность изменений и устойчивость, пусть лучше БД обеспечивает.
В случае in-process понятие БД расплывается, то бишь граница БД и прикладного кода чисто условная. Почему бы не рассмотреть вариант базовых классов транзакций и механизмов по ее работе?
Здравствуйте, vdimas, Вы писали:
AVK>>4) Допустимо ли требование первичного ключа типа GUID? V>-
Традиционный вопрос — почему?
AVK>>2) Достаточно ли самого простого варианта, или нужна возможность подкрузки в кейсет части данных? V>не совсем понятно, какая догрузка имеется в виду?
Обычно в кейсете содержаться только первичные ключи. Однако для некоторых алгоритмов может обязательно понадобится какое нибудь поле. Тогда выгоднее выгрузить в кейсет часть данных.
AVK>>3) Нужна ли многостадийная загрузка или подгрузка в 2 стадии — кейсет и остальные данные? Или может еще какой вариант? V>3-й вариант — загрузка каждого элемента или группы элементов по требованию (это имелось ввиду?).
Да.
AVK>>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов? V>скорее да, чем нет... ибо удобно, да и опять же
В чем удобство?
V>, возможно захочется тулзы делать.
Тому, кому захочется и флаг в руки.
AVK>>2) Что лучше — выборки или навигационный способ(курсоры). V>Оба хороши, каждый для своего
Они взаимозаменямы, так что основным должен быть какой то один.
AVK>>3) Что лучше — декларативный sql-like синтаксис или функциональный стиль? V>будет свой язык???
Нет.
AVK>>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД? V>трудный вопрос... А как насчет проекций и отчетов?
Проекции типизированные, отчеты — проблема тех, кто эти отчеты будет рисовать. Опять же — рефлекшен и полиморфизм никто не отменял.
AVK>>Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек? V>Вряд ли это легко без специального инструментария по смене типа. Т.е. мы поменяли имя и тип колонки/поля. Если эти действия не трекить, но непонятно, какая колонка куда поменялась...
Это элементарно решается привязыванием ко всем элементам метаданных уникального идентификатора. Если идентификатор другой, значит это другая колонка. Если нет — значит та же.
V> В общем, если речь идет о дотнет (насколько я понял), то типы и результирующие сборки для подобной БД нужно разрабатывать в некоем своем инструменте, с поддержкой такой реструктуризацией.
Совсем не обязательно.
AVK>>Какие еще аспекты БД было бы интересно рассмотреть с точки зрения описанной задачи? V>Политики владения/связи. Привязать сюда же GC для зависимых данных (почему бы и нет?)
Да вобщем особых проблем нет. Я как то даже в рпабочей системе такую штуку делал. Другое дело имеет ли смысл такое встраивать в БД?
Здравствуйте, vdimas, Вы писали:
V>Желательны оба варианта. В первом варианте неплохо бы получить "сырой" интерфейс на какие-нить row set-ы, чтобы помимо декларативного SQL иметь возможность для императивных циклических алгоритмов.
А зачем этот вариант нужен для однопользовательской БД?
AVK>>3) Описание метаданных
V>Не понятен вопрос. Речь идет о возможном РАСШИРЕНИИ стандартных метаданных? (стандартные — ну там тип поля и ограничения, типа nullable, участие в индексе или ограничения в виде SQL)
Нет никаких стандартных.
AVK>>4) Способ формирования запросов
V>Если in-proccess, то доп. через "сырые" интерфейсы доступа к данным.
Здравствуйте, GlebZ, Вы писали:
GZ>Курсор как таковой мало интересен и малофункицонален и неудобен по сравнению с тем же IEnumerator.
А по моему курсор и должен имплементировать IEnumerator. То есть это одно и тоже.
GZ>Насчет ключей есть другая думка. В реляционных базах данных есть несколько типов join. Один из них построен на хеше. То есть, у нас есть два отношения. Один из них меньше другого. При join, база данных строит хеш-таблицу RID по маленькому списку, и затем просто находит значения для большого списка и соединяет. Очень действенный механизм. Поскольку уже никто не возражает что ключ должен быть глобально уникальным для БД, и синтетическим, то вполне можно использовать именно хеширование. Кроме того, это даст нам путь быстрого нахождение одного объекта.
Во-во. Точно. Индексы по первиному ключу надо делать хэш-таблицей, а не деревом.
Здравствуйте, AndrewVK, Вы писали:
S>>А вот БД как абстрактный класс даст возможность применять намного больше фантазии и инструменты для отражения различных классов но такую БД.
AVK>Ага, а заодно потратить несколько лишних мегабаксов на проект.
Зря ты так считаешь. Конфигуратор аля 1С со своими набором классов не стот мегабаксы, но в отличие от 1С возможно будет возможно расширение за счет новых классов. Они тоже свою БД сделали правда ориентированную на SQL а зря, хотя и универсально.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, stalcer, Вы писали:
S>Во-во. Точно. Индексы по первиному ключу надо делать хэш-таблицей, а не деревом.
К тебе тот же вопрос — как обеспечить малое количество дисковых операций при добавлении или удалении элементов? Стандартная техника с бакетами, используемая в нетовских хештаблицах для диска мало подходит.
Здравствуйте, AndrewVK, Вы писали:
AVK>>>И при чем здесь функциональная форма? Ты декларативную привел. GZ>>Перепиши в функциональных терминах, будет то же самое. Проблема существует. AVK>Может быть. Но какое это имеет отношение к функциональному стилю?
Ну поробуй построить построитель запросов для почтовика типа outlook.
У нас есть письма. У нас есть адресная книга. Все это показывается в едином окне. У пользователя существуют рычаги того, как ему показывать, какие поля из письма или адресной книги, сделать фильтр по любому полю, отсортироваться по любому полю.
AVK>>>Неа. Я уже совершенно потерялся и не могу понять, что ты хочешь доказать. GZ>>Что keyset не нужен. AVK>В ООБД? Возможно. А вот в реляционных иногда очень даже.
Только не keyset. Повторюсь, неэффективно. К тому же еще я не уверен что при проекции вообще мы будем знать по какому id адресоваться.
AVK>А вот именно этот вопрос я и задавал. Ответов я знаю несколько. Можно анализировать IL, можно отказаться от лямбд в операции проекции, можно использовать LINQ.
Linq при сложной проекции функциклирует в read only. Анализировать IL — не понял. Отказаться можно, но тяжко. Больно бенефит хороший.
Фактически мы можем сохранять любой объект имеющий все not null поля(PK — также not null поле). Но тут еще один вопрос. Информация о реальном объекте находится в запросе а не в типе, и зависит от запроса и метаданных. В случае если мы изменим запрос, или подредактируем not null, у нас типы могут просто полететь в программе. Насколько это хорошо, сомневаюсь.
Еще проблема есть другая. Мы делаем такой запрос(пишу в SQL):
select a.*, b.id from a outer join b on (a.id=b.id)
И при этом b.id является not null полем, которое не всегда подгружается. Чую здесь будут проблемы в типах.
Вобщем лучше этим пока не заморачиваться, и запретить лямбду в проекции. Либо сделать дополнительно ручник. То есть ручное сохранение.
GZ>>Легко. Но надо сначало со структурой хранения. Хеш функция ведь должна по чему-то адресоваться. AVK>Структура хранения — страничный файл.
Ну смотри,
1-32 — байт относительный адрес страницы и относительный адрес значения в странице.
Например, у нас 8 килобайтная страницы. Каждый физический указатель — 8 байт. На странице 8кБ/8=1024 значений. Как результат для получения значения в странице hash&0x3FF. У нас осталось 22 бита с помощью которых мы будем адресовать страницы. Что в общем случае значит — адресацию 31 миллиардов значений. Число вполне достойное и не настольной системы.
Однако при этом надо думать о несовпадении удаленных и созданных значений индексов. Вот на это, мы и употребим оставшихся 32 бита. То есть будет некоторый счетчик уникальности hash значений. Вероятность совпадения 1/(2*32) — практически космическая, в особенности для настольных систем. В данном случае, я бы подумал даже о том, как сохранить информацию о типе. Я думаю, она очень пригодится на программном уровне. Допустим, отнять биты у адресации, и вероятности.
Единственный недостаток. Страницы не могут уменьшаться. Единственное когда они могут уменьшиться, операция типа truncate table или удаление. В случае уменьшения, адресация теряется.
Что касается создания, удаления. В данном случае предлагается использовать такой же механизм, как и для страниц таблиц. Только там есть степень заполненности, а нам нужно просто иметь bitmap, есть пустое или нет. Фактически поиск будет ограничен поиском в рамках страницы.
Здравствуйте, AndrewVK, Вы писали:
AVK>К тебе тот же вопрос — как обеспечить малое количество дисковых операций при добавлении или удалении элементов? Стандартная техника с бакетами, используемая в нетовских хештаблицах для диска мало подходит.
А какая разница? Вот, например, надо удалить 10 случайно выбранных объектов. И деревянный индекс и хэш-табличный ты будешь изменять в 10-и местах. И никакой локальности не будет.
Так? Или я не прав?
Здравствуйте, stalcer, Вы писали:
S>Здравствуйте, AndrewVK, Вы писали:
AVK>>К тебе тот же вопрос — как обеспечить малое количество дисковых операций при добавлении или удалении элементов? Стандартная техника с бакетами, используемая в нетовских хештаблицах для диска мало подходит.
S>А какая разница? Вот, например, надо удалить 10 случайно выбранных объектов. И деревянный индекс и хэш-табличный ты будешь изменять в 10-и местах. И никакой локальности не будет. S>Так? Или я не прав?
Почти да. Фрагментация сильно влияет на чтении, и значительно меньше на записи. В случае, если мы ведем лог, то мы удерживаем измененые блоки в памяти, и сбрасываем в лог изменения последовательно. Сброс основных данных идет в определенной время(нехватка памяти, комп ни фига не делает, или просто по таймеру). Сброс можно сделать последовательным, с меньшей фрагментацией.
Здравствуйте, Merle, Вы писали:
M>Это и есть нормальное решение, здесь не надо сложнее. Для поиска по таким текстам B+ все равно бесполезен, здесь надо все равно движек поиска по блобам отдельно подключать. А ключа размером с килобайт для B+ — за глаза.
Скажи мне. Вот MSSQL2000 позволяет создавать таблицы где записи с varchar по метаданным больше чем 8 кБ. При сохранении данных более 8 килобайт выдается ошибка. Ты когда-нибудь этой фичей пользовался?
Здравствуйте, GlebZ, Вы писали:
GZ>Скажи мне. Вот MSSQL2000 позволяет создавать таблицы где записи с varchar по метаданным больше чем 8 кБ.
Нет, 2000 не позволяет (он просто обрезает остаток), позволяет 2005й... Но уже 2000й позволял иметь начальную часть БЛОБ-а на основнй странице, а остальное хранить в отдельном месте.
Но при чем тут это?
Здравствуйте, GlebZ, Вы писали:
GZ>Ну поробуй построить построитель запросов для почтовика типа outlook.
Нафига оно мне? Построитель запросов для outlook выходит за рамки собственно БД. В отличие от внутрипрограммного доступа такая фича нужна далеко не всегда и сильно завязана на предметную область.
AVK>>>>Неа. Я уже совершенно потерялся и не могу понять, что ты хочешь доказать. GZ>>>Что keyset не нужен. AVK>>В ООБД? Возможно. А вот в реляционных иногда очень даже. GZ>Только не keyset. Повторюсь, неэффективно.
Можешь повторяться сколько хочешь, только это не аргумент. На практике я с его использованием получал огромный выигрышь во времени реакции системы на действия пользователей, особенно когда в самом запросе есть тяжелые джойны.
GZ> К тому же еще я не уверен что при проекции вообще мы будем знать по какому id адресоваться.
Тут все очень просто — надо проектировать запросы такими, чтобы знать все что необходимо.
GZ>Linq при сложной проекции функциклирует в read only.
BLToolkit тоже. На реальных проектах это не сильно беспокоит. Пойми, я не хочу сейчас обсуждать OR mapper и мне не очень нравится идея встраивать его в БД. А вне меппера ни о каких модификациях проекций речи даже не идет.
GZ>Фактически мы можем сохранять любой объект имеющий все not null поля(PK — также not null поле).
PK это readonly-поле. Что я точно знаю, так это то что ни в одной реальной задаче мне не понадобилось модифицировать значение первичного ключа.
GZ> Но тут еще один вопрос. Информация о реальном объекте находится в запросе а не в типе, и зависит от запроса и метаданных.
Только в том случае, если на уровне БД есть полиморфизм. В реляционных БД никакого полиморфизма нет.
GZ>
GZ>select a.*, b.id from a outer join b on (a.id=b.id)
GZ>
GZ>И при этом b.id является not null полем, которое не всегда подгружается. Чую здесь будут проблемы в типах.
Какие? Ты пойми — задача создания нужного типа и задача формирования проекции на него целиком на плечах прикладного программиста. Вот он пусть и разруливает. Не надо пытаться наворотить на движек БД все возможные задачи — чем он проще, тем качественнее.
GZ>1-32 — байт относительный адрес страницы и относительный адрес значения в странице. GZ>Например, у нас 8 килобайтная страницы. Каждый физический указатель — 8 байт. На странице 8кБ/8=1024 значений.
Каких значенией? Хеш-кодов?
GZ> Как результат для получения значения в странице hash&0x3FF.
Уже непонятно.
GZ> У нас осталось 22 бита с помощью которых мы будем адресовать страницы.
Еще менее понятно. Страница имеет свой собственный адрес, глобальный в пределах файла.
GZ>Однако при этом надо думать о несовпадении удаленных и созданных значений индексов. Вот на это, мы и употребим оставшихся 32 бита. То есть будет некоторый счетчик уникальности hash значений. Вероятность совпадения 1/(2*32) — практически космическая, в особенности для настольных систем. В данном случае, я бы подумал даже о том, как сохранить информацию о типе. Я думаю, она очень пригодится на программном уровне. Допустим, отнять биты у адресации, и вероятности.
Что то ты явно пропустил. И, главное — в хеше значения обязаны содержаться упорядоченно. Следовательно, если очередной PK нарушает порядок следования, следует переупорядочивать хеш на диске. Это очень дорого и как от этого избавиться ты так и не сказал.
GZ>Что касается создания, удаления. В данном случае предлагается использовать такой же механизм, как и для страниц таблиц.
Нельзя. В В+ дереве, в чем его прелесть, упорядоченность поддерживается автоматически. Использовать расщепление страниц для модификации хеш-таблицы не выйдет — там нужна линейная упорядоченность. Либо придется хранить в памяти соответствие между страницами хеш-индекса и порядком следования, что не очень здорово.
Здравствуйте, GlebZ, Вы писали:
S>>А какая разница? Вот, например, надо удалить 10 случайно выбранных объектов. И деревянный индекс и хэш-табличный ты будешь изменять в 10-и местах. И никакой локальности не будет.
GZ>Почти да. Фрагментация сильно влияет на чтении, и значительно меньше на записи.
Я не про фрагментацию, а про локальность. Т.е. если я удаляю 10 обектов, то мне придется исправить индекс в 10 местах. И вероятность того, что эти 10 мест будут далеко друг от друга (на разных страницах) — велика. И не потому, что присутствует фрагментация, а потому, что я взял 10 случайных объектов.
Абсолютно та же ситуация и на чтение.
И я не виже разницы в этом плане между деревом поиска и хэш таблицей.
Я утверждаю, что для того чтобы найти физический адрес объекта (тупла) по индексу необходимо обратиться как минимум к одной странице индекса. Для того, чтобы сделать изменения данных, затрагивающие индекс — нужно изменить как минимум одну страницу индекса.
Если изменений в транзакции много, то и страниц будет потенциально много, так как локальности — нет.
Здравствуйте, Merle, Вы писали:
GZ>>Скажи мне. Вот MSSQL2000 позволяет создавать таблицы где записи с varchar по метаданным больше чем 8 кБ. M>Нет, 2000 не позволяет (он просто обрезает остаток), позволяет 2005й... Но уже 2000й позволял иметь начальную часть БЛОБ-а на основнй странице, а остальное хранить в отдельном месте. M>Но при чем тут это?
А притом, что это практически одинаковое предложение. Сделать задачу такой, что когда нибудь она может стрельнуть. А то что стрельнет, по закону подлости — обязательно.
Здравствуйте, GlebZ, Вы писали:
GZ>А притом, что это практически одинаковое предложение.
Давай без практически. Ты что, действительно разницы не видишь?
Не имеет практического смысла делать ключ для B+ длиннее килобайта, вне зависимости от длинны самого поля.
GZ> Сделать задачу такой, что когда нибудь она может стрельнуть.
Здесь нечему стрелять. Вообще.
GZ> А то что стрельнет, по закону подлости — обязательно.
Приведи мне пример задачи, где пригодился бы поиск по B+ с ключем длиннее килобайта.
Здравствуйте, AndrewVK, Вы писали:
AVK>>>4) Допустимо ли требование первичного ключа типа GUID? V>>-
AVK>Традиционный вопрос — почему?
Да что-то не нравится его представление в дотнет. Нет чтобы сделать 2 лонга, там россыпь байт и прочего, и банальное сравнение не ахти какое быстрое.
Неужели Int64 мало? У нас же не будет распределенности, генерить ключи в одном месте будем.
AVK>>>1) Необходим ли SQL или любой другой текстовый декларативный язык запросов? V>>скорее да, чем нет... ибо удобно, да и опять же
AVK>В чем удобство?
Иметь возможность просмотреть данные отдельно от разрабатываемой системы.
V>>, возможно захочется тулзы делать.
AVK>Тому, кому захочется и флаг в руки.
В принципе я об этом и говорю. SQL можно как внешнюю либу прикрутить.
AVK>>>2) Что лучше — выборки или навигационный способ(курсоры). V>>Оба хороши, каждый для своего
AVK>Они взаимозаменямы, так что основным должен быть какой то один.
Если предоставлять доступ к кишкам, то стоит оптимизировать курсоры, ИМХО.
AVK>>>2) Допустим ли (и возможен ли?) полный отказ от нетипизированных данных (нетипизированных на уровне строки) при работе с БД? V>>трудный вопрос... А как насчет проекций и отчетов?
AVK>Проекции типизированные, отчеты — проблема тех, кто эти отчеты будет рисовать. Опять же — рефлекшен и полиморфизм никто не отменял.
Угу, как и IBindingList и т.д. Может быть. Разумеется, типизированность рулит и упрощает разработку этого дела.
AVK>>>Нужна ли поддержка автоматической реструктуризации данных при смене типов, встроенная в движек? V>>Вряд ли это легко без специального инструментария по смене типа. Т.е. мы поменяли имя и тип колонки/поля. Если эти действия не трекить, но непонятно, какая колонка куда поменялась...
AVK>Это элементарно решается привязыванием ко всем элементам метаданных уникального идентификатора. Если идентификатор другой, значит это другая колонка. Если нет — значит та же.
Я пока плохо представляю, как это будет работать вне специализированной системы разработки. Наверно у тебя сложилось некое представление об этом
AVK>>>Какие еще аспекты БД было бы интересно рассмотреть с точки зрения описанной задачи? V>>Политики владения/связи. Привязать сюда же GC для зависимых данных (почему бы и нет?)
AVK>Да вобщем особых проблем нет. Я как то даже в рпабочей системе такую штуку делал. Другое дело имеет ли смысл такое встраивать в БД?
Да. Абсолютно любая система с использованием БД обыгрывает всякие ситуации по владению-времени жизни связанных объектов. Иногда БД помогает (MS SQL начиная с 2000-го), иногда просто ограничивается накладыванием ограничений, и тогда разработчики сами делают одну и ту же тупую работу из проекта в проект...
Здравствуйте, AndrewVK, Вы писали:
AVK>Нафига оно мне? Построитель запросов для outlook выходит за рамки собственно БД. В отличие от внутрипрограммного доступа такая фича нужна далеко не всегда и сильно завязана на предметную область.
Я тебе предложил примерно показать область применения, ты показал. И тут оказывается что и это на данной шняге строить или невозможно, или неудобно. Нужна цель и требования. Тогда результат хотя бы кому-нибудь (кроме тебя, поскольку ты один сможешь подогнать задачу под свои требования) будет нужн.
AVK>>>>>Неа. Я уже совершенно потерялся и не могу понять, что ты хочешь доказать. GZ>>>>Что keyset не нужен. AVK>>>В ООБД? Возможно. А вот в реляционных иногда очень даже. GZ>>Только не keyset. Повторюсь, неэффективно.
И часто ты пользовался именно keyset?(это ведь только один из курсоров). Логика построения запросов для серверных курсоров достаточно сложная вещь. Не знаю как для MSSQL, но для Oracle — это совершенно отдельная математика. Для MSSQL наверное тоже, просто он делает это неявно.
AVK>Можешь повторяться сколько хочешь, только это не аргумент. На практике я с его использованием получал огромный выигрышь во времени реакции системы на действия пользователей, особенно когда в самом запросе есть тяжелые джойны.
А вообще, при тяжелых join именно keyset применим?
GZ>> К тому же еще я не уверен что при проекции вообще мы будем знать по какому id адресоваться. AVK>Тут все очень просто — надо проектировать запросы такими, чтобы знать все что необходимо. GZ>>Linq при сложной проекции функциклирует в read only. AVK>BLToolkit тоже. На реальных проектах это не сильно беспокоит. Пойми, я не хочу сейчас обсуждать OR mapper и мне не очень нравится идея встраивать его в БД. А вне меппера ни о каких модификациях проекций речи даже не идет.
GZ>>Фактически мы можем сохранять любой объект имеющий все not null поля(PK — также not null поле).
AVK>PK это readonly-поле. Что я точно знаю, так это то что ни в одной реальной задаче мне не понадобилось модифицировать значение первичного ключа.
+1
Еще любое аггрегируемое значение, также может быть read only.
GZ>> Но тут еще один вопрос. Информация о реальном объекте находится в запросе а не в типе, и зависит от запроса и метаданных. AVK>Только в том случае, если на уровне БД есть полиморфизм. В реляционных БД никакого полиморфизма нет.
Запрос подтвержен изменениям.
GZ>>
GZ>>select a.*, b.id from a outer join b on (a.id=b.id)
GZ>>
GZ>>И при этом b.id является not null полем, которое не всегда подгружается. Чую здесь будут проблемы в типах.
AVK>Какие? Ты пойми — задача создания нужного типа и задача формирования проекции на него целиком на плечах прикладного программиста. Вот он пусть и разруливает. Не надо пытаться наворотить на движек БД все возможные задачи — чем он проще, тем качественнее.
GZ>>1-32 — байт относительный адрес страницы и относительный адрес значения в странице. GZ>>Например, у нас 8 килобайтная страницы. Каждый физический указатель — 8 байт. На странице 8кБ/8=1024 значений.
AVK>Каких значенией? Хеш-кодов?
Нет. Первичный ключ — это логическое значение. Результат работы функции — физическое значение. То есть, на страницах должен быть список физических адресов.
GZ>> Как результат для получения значения в странице hash&0x3FF. AVK>Уже непонятно.
Это относительный индекс в массиве физических адресов.
GZ>> У нас осталось 22 бита с помощью которых мы будем адресовать страницы.
AVK>Еще менее понятно. Страница имеет свой собственный адрес, глобальный в пределах файла.
В данном случае нет. Это относительный адрес страницы. То есть номер страницы относительно первой в списке страниц на котором лежит данный индекс.
Вообще посмотри внимательно строение файлов MSSQL или Oracle. Лучше MSSQL. Он проще чем Oracle, и в нем нет ног от старых дисковых систем. Файл разделен на сегменты. Сегменты обеспечивают дефрагментированное чтение таблиц. Иначе будет диск головкой слишком часто чирикать. Сегменты разделены на страницы. Страницы это гранулярность чтения и нагрузки на память. То есть, тебе нужно будет удерживать в памяти именно страницы. Цифры что сегмент — 64кБ, а страница 8 кБ, я думаю надо будет оставить. Не спроста они такие.
GZ>>Однако при этом надо думать о несовпадении удаленных и созданных значений индексов. Вот на это, мы и употребим оставшихся 32 бита. То есть будет некоторый счетчик уникальности hash значений. Вероятность совпадения 1/(2*32) — практически космическая, в особенности для настольных систем. В данном случае, я бы подумал даже о том, как сохранить информацию о типе. Я думаю, она очень пригодится на программном уровне. Допустим, отнять биты у адресации, и вероятности.
AVK>Что то ты явно пропустил. И, главное — в хеше значения обязаны содержаться упорядоченно. Следовательно, если очередной PK нарушает порядок следования, следует переупорядочивать хеш на диске. Это очень дорого и как от этого избавиться ты так и не сказал.
Они не должны лежать упорядоченно. Это им не нужно. Это синтетический ключ, поиска по диапазону к нему не нужен, join в котором нужна сортировка также нам не нужны. Так зачем?
GZ>>Что касается создания, удаления. В данном случае предлагается использовать такой же механизм, как и для страниц таблиц. AVK>Нельзя. В В+ дереве, в чем его прелесть, упорядоченность поддерживается автоматически. Использовать расщепление страниц для модификации хеш-таблицы не выйдет — там нужна линейная упорядоченность. Либо придется хранить в памяти соответствие между страницами хеш-индекса и порядком следования, что не очень здорово.
Повторюсь, упорядочивать значения нам не нужно. А не нужно балансировать хеш. Заполненность полная. У нас либо хватает значений, либо не хватает. Если нам нужно новое значение, то в bitmap мы находим страницу обозначенную что у нее есть пустой слот, находим ее и сохраняем. Если таковой нет, то добавляем новую страницу в индекс. Если у нас полностью заполнена страница, то мы добавляем изменяем bitmap и добавляем к транзакции. Вероятность добавления к транзакции 1/1024.
AVK>Разница самая обыкновенная — для того чтобы работала хеш-таблица хеши должны быть линейно упорядоченны. Как обеспечивается это в памяти я знаю, а вот как обеспечить это на диске пока не ясно.
Ты можешь организовать диапозоны хэшей на определенных страницах. Внутри которой хэши отсортированы.
Начинается на уровне четный нечетный
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Merle, Вы писали:
GZ>> А то что стрельнет, по закону подлости — обязательно. M>Приведи мне пример задачи, где пригодился бы поиск по B+ с ключем длиннее килобайта.
Outlook. Письма, задачи e.t.c.
Здравствуйте, GlebZ, Вы писали:
GZ>Я тебе предложил примерно показать область применения, ты показал. И тут оказывается что и это на данной шняге строить или невозможно, или неудобно.
Пока еще ничего не оказалось.
GZ> Нужна цель и требования.
Ага, ты еще ТЗ попроси. Если бы у меня была четкая картина задачи, я бы тут философские разговоры не разводил. Все что я могу на данный момент сказать, я уже сказал. Цели и требования точно так же уточнять надо. На данном этапе встраивать в движек универсальные текстовые запросы, только потому что есть одна весьма специфичная задача, мне не кажется целесообразным.
GZ>>>Только не keyset. Повторюсь, неэффективно. GZ>И часто ты пользовался именно keyset?
На десктопе часто.
GZ>(это ведь только один из курсоров). Логика построения запросов для серверных курсоров достаточно сложная вещь.
Я серверные не использую, я использую клиентские. И здесь речь, ты еще не забыл, о настольной БД. Проблемы серверных БД меня в данном контексте не волнуют, особенно проблемы многопользовательского доступа.
GZ>А вообще, при тяжелых join именно keyset применим?
Еще как. А что, у тебя с этим какие то проблемы?
AVK>>Только в том случае, если на уровне БД есть полиморфизм. В реляционных БД никакого полиморфизма нет. GZ>Запрос подтвержен изменениям.
Каким?
GZ>>>1-32 — байт относительный адрес страницы и относительный адрес значения в странице. GZ>>>Например, у нас 8 килобайтная страницы. Каждый физический указатель — 8 байт. На странице 8кБ/8=1024 значений.
AVK>>Каких значенией? Хеш-кодов? GZ>Нет. Первичный ключ — это логическое значение. Результат работы функции — физическое значение. То есть, на страницах должен быть список физических адресов.
Физических адресов чего? Записей в кластерном индексе? Тогда что мы увидим в прикладном коде?
AVK>>Еще менее понятно. Страница имеет свой собственный адрес, глобальный в пределах файла. GZ>В данном случае нет.
Значит фиговый случай, поскольку несовместим с остальными данными.
GZ>Вообще посмотри внимательно строение файлов MSSQL или Oracle. Лучше MSSQL. Он проще чем Oracle, и в нем нет ног от старых дисковых систем. Файл разделен на сегменты. Сегменты обеспечивают дефрагментированное чтение таблиц. Иначе будет диск головкой слишком часто чирикать. Сегменты разделены на страницы. Страницы это гранулярность чтения и нагрузки на память. То есть, тебе нужно будет удерживать в памяти именно страницы. Цифры что сегмент — 64кБ, а страница 8 кБ, я думаю надо будет оставить. Не спроста они такие.
Все это здорово, но я что то не улавливаю какое это имеет отношение к разговору.
AVK>>Что то ты явно пропустил. И, главное — в хеше значения обязаны содержаться упорядоченно. Следовательно, если очередной PK нарушает порядок следования, следует переупорядочивать хеш на диске. Это очень дорого и как от этого избавиться ты так и не сказал. GZ>Они не должны лежать упорядоченно. Это им не нужно.
Да, тяжело тебя понять. Попробуем сделать еще одно предположение — ты хочешь использовать в качестве ключа физический адрес записи в кластерном индексе? А что тогда делать при расщеплении его страницы?
GZ> Это синтетический ключ, поиска по диапазону к нему не нужен, join в котором нужна сортировка также нам не нужны. Так зачем?
Что зачем? Зачем упорядоченно? Затем, что хеш-функция должна при помощи простых арифметических операций вычислить адрес записи.
Вобщем я не могу понять, что за алгоритм ты имеешь ввиду. Попробуй объяснить его поподробнее.
Здравствуйте, GlebZ, Вы писали:
M>>Приведи мне пример задачи, где пригодился бы поиск по B+ с ключем длиннее килобайта. GZ>Outlook. Письма, задачи e.t.c.
Ты хорошо представляешь что такое B+? При большем размере ключа B+ уже не эффективен.
И что ты собрался искать в письмах по ключам такого размера?
Еще раз говорю, бля поиска в больших текстах, совсем другие механизмы нужны...
Здравствуйте, Serginio1, Вы писали:
S>Ты можешь организовать диапозоны хэшей на определенных страницах. Внутри которой хэши отсортированы. S> Начинается на уровне четный нечетный
Могу. Но вопрос остается прежним — что делать при модификациях?
Здравствуйте, vdimas, Вы писали:
V>Да что-то не нравится его представление в дотнет.
Это несерьезно.
V> Нет чтобы сделать 2 лонга, там россыпь байт и прочего, и банальное сравнение не ахти какое быстрое.
На уровне БД можно использовать что угодно, а GUID формировать только на уровне выдачи результата.
V>Неужели Int64 мало?
Мало. Потому что GUID обладает замечательной особенностью — отпадает необходимость в генераторах или автоинкременторах в движке БД и операциях его считывания после добавления записи. Грубо говоря — я могу знать PK объекта даже не обращаясь к БД.
AVK>>Это элементарно решается привязыванием ко всем элементам метаданных уникального идентификатора. Если идентификатор другой, значит это другая колонка. Если нет — значит та же.
V>Я пока плохо представляю, как это будет работать вне специализированной системы разработки. Наверно у тебя сложилось некое представление об этом
Так и будет. Объявляем тип, регистрируем его в БД. Что там нужно специализированного? Ну разве что план запроса посмотреть.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>Ты можешь организовать диапозоны хэшей на определенных страницах. Внутри которой хэши отсортированы. S>> Начинается на уровне четный нечетный
AVK>Могу. Но вопрос остается прежним — что делать при модификациях?
Перераспределение при переполнении но только части страниц. Хотя индекс по хэшам длинных индексов имхо выгодней, а для небольших по размеру ключей выигрыш для хэш таблиц небольшой , учитывая кэширования верхних страниц индекса.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
AVK>>Могу. Но вопрос остается прежним — что делать при модификациях? S>Перераспределение при переполнении но только части страниц.
А что делать с внешними ключами?
S> Хотя индекс по хэшам длинных индексов имхо выгодней, а для небольших по размеру ключей выигрыш для хэш таблиц небольшой , учитывая кэширования верхних страниц индекса.
Он выгоднее в памяти. А вот работающий алгоритм для диска я пока не услышал.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Могу. Но вопрос остается прежним — что делать при модификациях? S>>Перераспределение при переполнении диапозона но только части страниц.
AVK>А что делать с внешними ключами?
А причем тут они???? Контроль ссылочноти как то не связан с поиском по ПК.
Самый простой способ Сделать индекс типа, ПK,IDТаблицы,ПКвтаблице. И он как то не привязан к к организации хранения первичного ключа.
S>> Хотя индекс по хэшам длинных индексов имхо выгодней, а для небольших по размеру ключей выигрыш для хэш таблиц небольшой , учитывая кэширования верхних страниц индекса.
AVK>Он выгоднее в памяти. А вот работающий алгоритм для диска я пока не услышал.
Как это не услышал??? Хотя я и не стронник применения Хэш таблиц для ПК, но реально они существуют и используются и достаточно хорошо описаны.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>>>Могу. Но вопрос остается прежним — что делать при модификациях? S>>Перераспределение при переполнении но только части страниц. AVK>А что делать с внешними ключами?
Внешние ключи адресуются по primary key. Рельные физические адреса надо изменять в связанных индексах по любому.
S>> Хотя индекс по хэшам длинных индексов имхо выгодней, а для небольших по размеру ключей выигрыш для хэш таблиц небольшой , учитывая кэширования верхних страниц индекса. AVK>Он выгоднее в памяти. А вот работающий алгоритм для диска я пока не услышал. здесь
V>> Нет чтобы сделать 2 лонга, там россыпь байт и прочего, и банальное сравнение не ахти какое быстрое.
AVK>На уровне БД можно использовать что угодно, а GUID формировать только на уровне выдачи результата.
+1
V>>Неужели Int64 мало?
AVK>Мало. Потому что GUID обладает замечательной особенностью — отпадает необходимость в генераторах или автоинкременторах в движке БД и операциях его считывания после добавления записи. Грубо говоря — я могу знать PK объекта даже не обращаясь к БД.
Собсно, я для этого использую счетчики в программе. И я тоже знаю ПК объекта заранее и даже могу понасоздавать в памяти графы связанных объектов и затем в один присест сохранить. Думаешь, дело упирается в генерацию ПК???
В одном из проектов, когда я оптимизировал ПК, то бишь уменьшил где только это возможно ширину данных (с 32 до 16 или даже 8 бит) у меня быстродействие базы выросло более чем вдвое. Ты же не забывай, что таблицы, которые хранят наибольшее число строк (сотни тысяч и миллионы), обычно представляют из себя некие "движения", и в этих данных половина полей — значения ПК связанных (справочних и не только) таблиц. Т.е. одно дело, когда у меня в строке данных примерно 8 ключей с типами от int8 до int32, и другое дело — 8 гвидов...
Для того, чтобы не страдать переполнением малоразрядных счетчиков, я использую кеш удаленных ключей, для повторного их использования на новых объектах. В общем, все ради сужения типа, представляющего ключ, ибо это в разы повышает эффективность.
Здравствуйте, stalcer, Вы писали:
S>Нас вообще-то должно волновать только "select folder.*, u.unreadSize".
Нет, это волнует прикладного программиста, который будет пользовать эту гипотетическую БД. S>Остальное, то что внутри запроса, как я понимаю, дело компилятора запроса.
А разработчиков БД как раз это и волнует. Точнее, волнует вообще возможность type inference. S>Ну я виже два способа: первый — анонимные типы, второй — явно указанный тип, т.е:
Это все очень хорошо, но непонятно, как будет работать на практике. Никто не собирается делать еще один компилятор C#-подобного языка. Все должно работать по-настоящему.
Если отказаться от type inference, то все запросы будут возвращать что-то приводимое к IEnumerable<T>, где T — один из хранимых в БД типов.
Если не отказываться, то запросы должны будут возвращать что-то типа дотнетовых датасетов (т.е коллекций строк, каждая из которых суть список пар ключ/значение).
S>Имхо, оба способа должны присутствовать. И разве этого будет недостаточно?
Это ты здорово придумал. Вот только я не очень понял, на каком это языке. C# такого пока не позволяет. Я не очень внимательно слежу за тем, что будет позволено в C# 3.0.
В целом мне, конечно, идея нравится. Проблема только в том, что для обеспечения второго способа (точный именованный тип) тебе фактически нужен первый (а потом ты просто перекладываешь данные из анонимного типа в именованный путем явного вызова конструктора).
Вот такая вот петрушка. Надо копать в анонимные типы в третьем шарпе, чтобы понять, что там вообще можно сделать.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, stalcer, Вы писали: S>Это, имхо, скорее плохо, чем хорошо. Вот удобный синтаксис специально для join'ов по FK — это хорошо. Но ограниение...
Я просто очень давно не видел других джойнов. Разве что в отчетах... Но там обычно вообще такая дикость присутствует, что мама дорогая...
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, GlebZ, Вы писали:
GZ>> Для кластерного индекса пользователь может использовать любой свой, основанный на B+ индексе. M>Так ли велик будет выигрыш от приседания вокруг хэш-таблицы, если все равно надо поддерживать два типа индексов, причем хэш-таблица какая-то не очень тривиальная получается?
Во первых я там ошибся, должно быть B+ дерево.
А выйгрыш получится достаточно большой. У нас не будет надобности хранить значения от primary key. То есть в случае 8 байтового значения индекс будет в два раза меньше. В случае guid'а еще больше. Как результат, у нас увеличивается вероятность что на мелких таблицах(коих иногда очень даже много) мы весь primary key уместим на одной странице. Это должно снизить нагрузку на кэш. Во вторых, у нас в отличие от B дерева — нет надобности сравнивать значения. То есть в случае если все лежит в кэше, поиск значения мгновенный. Логарифметическая сложность поиска сохраняется, только в отличие от Nlog(N) получается log(N). Но опять же, повторюсь, при полном сканировании индекса, он как минимум в два раза меньше. Что должно повлиять на быстроту join. Ну и еще мы получаем практически готовый эффективный join. Надо просто добавить сравнение.
Здравствуйте, AndrewVK, Вы писали: AVK>К тебе тот же вопрос — как обеспечить малое количество дисковых операций при добавлении или удалении элементов? Стандартная техника с бакетами, используемая в нетовских хештаблицах для диска мало подходит.
Если мне вернут моего Гарсиа-Молина, то я расскажу, как устроены хеш-индексы в СУБД. Там какая-то особенная хитрость применена для рехешинга при переполнении, благодаря чему вставки тоже ведут себя прилично. Конечно, никакие хеш-таблицы, реализованные c расчетом на произвольный доступ, в СУБД непригодны.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, GlebZ, Вы писали:
GZ>То есть в случае 8 байтового значения индекс будет в два раза меньше. В случае guid'а еще больше.
Эффект от размра ключа вылезает только на очень больших таблицах, в несколько миллионов записей, а на маленьких его практически незаметно.
К тому же это PK, то есть вытягивание одной записи, а это одна из самых дешевых операций, тут нет необходимости выжимать максимальную производительность.
GZ> Как результат, у нас увеличивается вероятность что на мелких таблицах(коих иногда очень даже много) мы весь primary key уместим на одной странице. Это должно снизить нагрузку на кэш.
Плюс-минус пара страниц на кеш — болшой роли не играет, так что для малых размеров реально выигрыша практически не будет.
GZ> Во вторых, у нас в отличие от B дерева — нет надобности сравнивать значения. То есть в случае если все лежит в кэше, поиск значения мгновенный. Логарифметическая сложность поиска сохраняется, только в отличие от Nlog(N) получается log(N).
Если все в кеше, то это все просто другой порядок малости по сравнению с обращением к диску. К тому же, как я уже говорил, поиск одной записи не самая критичная ко времени операция.
GZ> Ну и еще мы получаем практически готовый эффективный join. Надо просто добавить сравнение.
К сожалению hash join эффективен далеко не всегда.
Здравствуйте, Sinclair, Вы писали:
S>Я просто очень давно не видел других джойнов. Разве что в отчетах... Но там обычно вообще такая дикость присутствует, что мама дорогая...
Спасибо. Я как раз и интересуюсь статистикой: нужны ли произвольные джоины или достатоно только по ссылоным полям (FK). Это для проектирования языка запросов.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
AVK>>>Он выгоднее в памяти. А вот работающий алгоритм для диска я пока не услышал. S>>http://zeus.sai.msu.ru:7000/programming/theory/sorting/sorting2.shtml#5_2 M>Из всего того что там сказано, к методам хэширования на диске относятся две фразы: M>1.
Линейное хеширование: Если возникает потребность в расщеплении, то записи перераспределяются по блокам так, чтобы адресация осталась правильной.
M>Отпадает по понятным причинам — слишком дорогое это удовольствие.
При фиксированнолм размере удовольствие бесплатное. Всё от задач.
А чем тебе не нравится Extendible Hashing. До миллиона элементов вполне приемлемая технология.
В этот размер умещается большинство справочников. M>
По базы данных: Тем не менее, похоже, что технология хэширования постепенно сольется с технологией B-деревьев и станет основной в мире баз данных.
M>Обнадеживает, но пока не актуально.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinclair, Вы писали:
S>>Нас вообще-то должно волновать только "select folder.*, u.unreadSize". S>Нет, это волнует прикладного программиста, который будет пользовать эту гипотетическую БД.
Я имею ввиду, что есть две подсистемы: компилятор запросов и API для выполнения запросов. Речь ведь шла про типизированный API. Так вот API требуется только список возвращаемых полей, остальное делает компилятор запросов.
S>>Остальное, то что внутри запроса, как я понимаю, дело компилятора запроса. S>А разработчиков БД как раз это и волнует. Точнее, волнует вообще возможность type inference.
А какие здесь проблемы. У любого выражения в типизированном языке (языке запросов) есть свой тип. И все.
S>>Имхо, оба способа должны присутствовать. И разве этого будет недостаточно? S>Это ты здорово придумал. Вот только я не очень понял, на каком это языке. C# такого пока не позволяет. Я не очень внимательно слежу за тем, что будет позволено в C# 3.0.
Первый способ на текущем C# не сделать никак.
То есть вывод один: если хочется типизированного API, то необходимо явно объявлять указывать тип возвращаемой запросом строки.
Я не особо слежу за развитием C#, но вроде они осознав это ввели язык запросов прямо в основной язык.
S>В целом мне, конечно, идея нравится. Проблема только в том, что для обеспечения второго способа (точный именованный тип) тебе фактически нужен первый (а потом ты просто перекладываешь данные из анонимного типа в именованный путем явного вызова конструктора).
Блин. Каюсь. И так тоже не получится. Если только C# поддерживал бы C++ подобные шаблонные ужасы .
Здравствуйте, GlebZ, Вы писали:
AVK>>Ага, ты еще ТЗ попроси. GZ>ТЗ нет. А вот vision — с удовольствием бы. Тогда было бы более понятно что строим и с кем конкурируем. И вообще границы задачи.
Если ты еще не понял — цель этого топика как раз и состоит в том, чтобы сформировать такой vision.
AVK>>На десктопе часто. GZ>Никогда. Лучше я десять раз перекачаю лишние данные, чем каждый раз обращаться к серваку. А десктопами, особо не занимался.
С этого и надо начинать.
AVK>>Я серверные не использую, я использую клиентские. И здесь речь, ты еще не забыл, о настольной БД. Проблемы серверных БД меня в данном контексте не волнуют, особенно проблемы многопользовательского доступа. GZ>Проблема серверных курсоров лежит в многопользовательском доступе, и только в нем. И больше нигде. Поэтому предлагаю размыть разницу между серверным и клиентским курсором. Тем более что у нас именно встроенная система.
Я что то не пойсу к чему ты ведешь? Ты можешь сколько угодно размывать границы, но проблем серверных курсоров в сабже не существует по определению. Так что и ограничения онных к нему неприменимы.
AVK>>Еще как. А что, у тебя с этим какие то проблемы? GZ>Я просто не понял, если ты держишь у себя результат join'a, то есть проекции от него, то каким образом ты его адресуешь? Или это только когда проекция одной таблицы?
Вместо джойна выбирается только таблица, которая содержит ключ. Например, в случае януса, самый тяжелый запрос джойнит таблицу сообщений с таблицей агрегатов по темам. Если использовать кейсет, то при выборке собственно кейсета этот джойн выкидывается и заменяется на банальный фильтр по форуму. А джойн при выборке данных уже не так страшен, потому что в 99% случаев дальше верхних двух десятков тем дело не идет.
GZ>На заключительном этапе мы пытаемся отрефакторить новое приложение так, чтобы пользователь хотя бы чайку при запросе не успел выпить. А достигается это рефакторингом запросов и схемы. А менять приложение в таком случае, не очень приятное занятие.
Линейное хеширование: Если возникает потребность в расщеплении, то записи перераспределяются по блокам так, чтобы адресация осталась правильной.
M>Отпадает по понятным причинам — слишком дорогое это удовольствие.
Ага, о чем я все время и говорил. Хеш индексы рулят, когда у нас есть массив данных, который не меняется. А если у нас идет постоянное обновление, то вылазит масса проблем, которые лично я не вижу смысла решать, потому что бенефит не такой уж и большой.
M>2. M>
По базы данных: Тем не менее, похоже, что технология хэширования постепенно сольется с технологией B-деревьев и станет основной в мире баз данных.
Здравствуйте, vdimas, Вы писали:
AVK>>Мало. Потому что GUID обладает замечательной особенностью — отпадает необходимость в генераторах или автоинкременторах в движке БД и операциях его считывания после добавления записи. Грубо говоря — я могу знать PK объекта даже не обращаясь к БД.
V>Собсно, я для этого использую счетчики в программе. И я тоже знаю ПК объекта заранее и даже могу понасоздавать в памяти графы связанных объектов и затем в один присест сохранить. Думаешь, дело упирается в генерацию ПК???
C Guid проще, связанность меньше. В твоем же случае придется передавать при создании внутрь объектов какой то контекст, содержащтй счетчики. Опять же заморочки с многопоточностью.
V>В одном из проектов, когда я оптимизировал ПК, то бишь уменьшил где только это возможно ширину данных (с 32 до 16 или даже 8 бит) у меня быстродействие базы выросло более чем вдвое. Ты же не забывай, что таблицы, которые хранят наибольшее число строк (сотни тысяч и миллионы), обычно представляют из себя некие "движения"
Ты не забывай, что речь идет не о БД для всяких ERP-подобных программ. Там другие решения, с другими требованиями.
V>Для того, чтобы не страдать переполнением малоразрядных счетчиков, я использую кеш удаленных ключей, для повторного их использования на новых объектах. В общем, все ради сужения типа, представляющего ключ, ибо это в разы повышает эффективность.
Насчет разов я сильно сомневаюсь. Я в свое время делал много тестов на эту тему — переход с int на guid в mssql отжирал максимум 20% производительности на очень мелких операциях.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
S>> При фиксированнолм размере удовольствие бесплатное. Всё от задач. M>Во-во, а задачи такие, что фиксированный размер только по большим праздникам.
S>>А чем тебе не нравится Extendible Hashing. M>
M>требует наличия в основной памяти справочного дерева.
S>>До миллиона элементов вполне приемлемая технология. M>А после миллиона что делать?
S>> В этот размер умещается большинство справочников. M>А не справочников? А что делать если не уместится?
M>Проблема в том что такой подход не обладает должной универсальностью и требует довольно серьезного расхода ресурсов, что в настольной системе вряд ли можно себе позволить.
Да??? На все если есть определённые кабы. Кроме того речь шла о не универсальности а возможности. Возможность такая есть.
Кроме того после определенного размера, не все дерево можно хранить в памяти. Все от реализации. В любом случае количество обращений к диску и вычислений двоичного поиска можно существенно снизить.А это для настольных систем более чем нужно.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
S>> При фиксированнолм размере удовольствие бесплатное. Всё от задач. M>Во-во, а задачи такие, что фиксированный размер только по большим праздникам.
S>>А чем тебе не нравится Extendible Hashing. M>
M>требует наличия в основной памяти справочного дерева.
S>>До миллиона элементов вполне приемлемая технология. M>А после миллиона что делать?
Вот не разобрался в сути алгоритма, а начинаешь критиковать.
Мы имеем дерево страниц. Алгортм таков сначало всй хранится в одной странице. При переполнении выделяется еще одна страница
в которую перемещаются данные с первым битом равным 1.
Так имеем дерево с разветвлением по первому биту. Затем при переполнении страницы она опять расчепляется на 2 и в дереве появляется узел но раздляет уже по 2 биту итд. Держать же само дерево можно на диске, первая страница так или иначе будет кэшировано вот и вся память. А выигрыш за счет дисковых операций очевиден. S>> В этот размер умещается большинство справочников. M>А не справочников? А что делать если не уместится?
Смотри выше M>Проблема в том что такой подход не обладает должной универсальностью и требует довольно серьезного расхода ресурсов, что в настольной системе вряд ли можно себе позволить.
Обладает универсальностью. Просто надо уметь готовить.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Да???
Да.
S>Кроме того речь шла о не универсальности а возможности. Возможность такая есть.
Нету, потому как не подходит под условие задачи.
S> В любом случае количество обращений к диску и вычислений двоичного поиска можно существенно снизить.
Каким образом? Если не все дерево в памяти хранить?
Здравствуйте, Serginio1, Вы писали:
S>Вот не разобрался в сути алгоритма, а начинаешь критиковать.
Я просто процитировал слова автора, где оговорено условие не подходящее под нашу задачу.
S> Держать же само дерево можно на диске, первая страница так или иначе будет кэшировано вот и вся память.
И чем это будет отличаться от B+?
S> А выигрыш за счет дисковых операций очевиден.
Очевиден лишний геморрой, и очевидно что выигрыша нет, так как все равно получаем B-дерево частично лежащее на диске. Та же конструкция, только в профиль, и ради чего спрашивается?
К тому же пойми, даже если мы получим здесь небольшой выигрыш, затраченных усилий это не оправдает, так как доставание одной записи не самая критичная операция.
S> Просто надо уметь готовить.
Во-во.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
S>>Вот не разобрался в сути алгоритма, а начинаешь критиковать. M>Я просто процитировал слова автора, где оговорено условие не подходящее под нашу задачу.
S>> Держать же само дерево можно на диске, первая страница так или иначе будет кэшировано вот и вся память. M>И чем это будет отличаться от B+?
S>> А выигрыш за счет дисковых операций очевиден. M>Очевиден лишний геморрой, и очевидно что выигрыша нет, так как все равно получаем B-дерево частично лежащее на диске. Та же конструкция, только в профиль, и ради чего спрашивается?
Не совсем. Это модификация и не Б дереват, бинарного дерева по хэшу. Внути страницы понятно может сортироваться.
А насчет гемороя и лишних усилий, то алгоритм такой хэш таблицы, намного проще. Правжа нужно учитывать возможную вырожденность.
Опять же всё зависит от задач. M>К тому же пойми, даже если мы получим здесь небольшой выигрыш, затраченных усилий это не оправдает, так как доставание одной записи не самая критичная операция.
Во первых я сам не являюсь сторонником, но выступаю за возможность и определённые бенефиты при использовании. Чем больше способов, тем больше гибкость. А категоричность не мой подход. S>> Просто надо уметь готовить. M>Во-во.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
M>К тому же пойми, даже если мы получим здесь небольшой выигрыш, затраченных усилий это не оправдает, так как доставание одной записи не самая критичная операция.
А для меня, например, критичная. Я вот ORM делаю, и там есть две основные оптимизации: подгрузка ассоциированных объектов батчем в отдельном запросе, т.е. where id in (:p0, :p1, ...), и подгрузка ассоциироваых объектов джоинами в том же запросе. И первый вариант работает в Oracle откровенно плохо. Намного хуже чем ждоины, хотя вроде почему бы...
Здравствуйте, Serginio1, Вы писали:
S> Не совсем. Это модификация и не Б дереват, бинарного дерева по хэшу. Внути страницы понятно может сортироваться.
И в чем разница?
S> А насчет гемороя и лишних усилий, то алгоритм такой хэш таблицы, намного проще.
Проще чем B+?
S> Правжа нужно учитывать возможную вырожденность. Опять же всё зависит от задач.
Понимаеш, тут как бы не стоит задачи разработать Оракл, чтобы на каждый сценарий свой тип индекса держать... Нужен подход +/- с одинаковым успехом решающий максимально широкий круг задач.
Здравствуйте, stalcer, Вы писали:
S>А для меня, например, критичная.
За счет чего? У тебя это наиболее частая операция?
S> Я вот ORM делаю, и там есть две основные оптимизации: подгрузка ассоциированных объектов батчем в отдельном запросе, т.е. where id in (:p0, :p1, ...), и подгрузка ассоциироваых объектов джоинами в том же запросе. И первый вариант работает в Oracle откровенно плохо. Намного хуже чем ждоины, хотя вроде почему бы...
Ну так и пользуйся join-ами, в чем проблема?
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
S>> Не совсем. Это модификация и не Б дереват, бинарного дерева по хэшу. Внути страницы понятно может сортироваться. M>И в чем разница?
S>> А насчет гемороя и лишних усилий, то алгоритм такой хэш таблицы, намного проще. M>Проще чем B+?
Однозначно. В Б+ деревьях очень много состояний в которое может попадать дерево. Мои исходники составляют 60 кб для Б+ в памяти. S>> Правжа нужно учитывать возможную вырожденность. Опять же всё зависит от задач. M>Понимаеш, тут как бы не стоит задачи разработать Оракл, чтобы на каждый сценарий свой тип индекса держать... Нужен подход +/- с одинаковым успехом решающий максимально широкий круг задач.
Вообщето весь сыр бор отсюда http://www.rsdn.ru/Forum/Message.aspx?mid=1824409&only=1
только и всего. А так я полностью согласен . И вообще у меня другой взгляд на строение БД, т.к.
универсальность не всегда есть хорошо. Но это моё большое ИМХО.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Merle, Вы писали:
M>За счет чего? У тебя это наиболее частая операция?
Ну да. Навигационный доступ ведь.
M>Ну так и пользуйся join-ами, в чем проблема?
А проблема в том, что запросы (оптимизирующие навигационный доступ) автоматически генерируются на основе статистики и с ждоинами этот алгоритм сложнее.
Или другой пример: надо выбрать (через ORM) все объекты определенного класса. ORM может сделать запрос так:
select*from MyClassTable
А может так:
сначала
selectidfrom MyClassTable
и потом серией запросов:
select * from MyClassTable where id in (:p0, :p1, ...)
Второй способ вроде бы предпочтительней, так как есть кэширование и не все объекты фактически нуждаются в загрузке. Но работает он почему-то гораздо медленнее.
То есть я, конечно, понимаю, что один запрос лучше нескольких. Но ведь я же не делаю запрос на каждый объект в отдельности, поэтому латентность СУБД + сети не всчет (это можно и доказать примером, делающим такое же количество других запросов, без id in (...)).
Так что скорость поиска по ключу имеет для меня принципиальное значение.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, GlebZ, Вы писали:
GZ>>То есть в случае 8 байтового значения индекс будет в два раза меньше. В случае guid'а еще больше. M>Эффект от размра ключа вылезает только на очень больших таблицах, в несколько миллионов записей, а на маленьких его практически незаметно.
Поясняю.
1. У нас десктор. Это не сервер где мы можем с честью адаптировать всю память. У нас может быть запущено несколько инстансов с разными базами. А нехватка памяти в услових GC — дорогое удовольствие.
2. У меня на больших приложения процентов 80 таблиц маленькие. Остальные 20% большие. Есть большая вероятность, что для десктопа этот процент маленьких таблиц будет доходить до 99%.
Поэтому считаю что каждый отданный килобайт — это отданный килобайт врагу. В отличие от серверных приложений, мы обязаны ограничивать размер используемой оперативной памяти.
M>К тому же это PK, то есть вытягивание одной записи, а это одна из самых дешевых операций, тут нет необходимости выжимать максимальную производительность.
Что значит самая дешевая? У тебя join то вытягивание становится массовой операцией которая может влиять в разы.
GZ>> Как результат, у нас увеличивается вероятность что на мелких таблицах(коих иногда очень даже много) мы весь primary key уместим на одной странице. Это должно снизить нагрузку на кэш. M>Плюс-минус пара страниц на кеш — болшой роли не играет, так что для малых размеров реально выигрыша практически не будет.
При ста маленьких таблиц? Играет.
GZ>> Во вторых, у нас в отличие от B дерева — нет надобности сравнивать значения. То есть в случае если все лежит в кэше, поиск значения мгновенный. Логарифметическая сложность поиска сохраняется, только в отличие от Nlog(N) получается log(N). M>Если все в кеше, то это все просто другой порядок малости по сравнению с обращением к диску. К тому же, как я уже говорил, поиск одной записи не самая критичная ко времени операция.
Самые критичные операции — join и сортировка. Для сортировки синтетический ключ бесполезен. Для join весьма. И именно ему надо будет вытаскивать по одному.
GZ>> Ну и еще мы получаем практически готовый эффективный join. Надо просто добавить сравнение. M>К сожалению hash join эффективен далеко не всегда.
Безусловно. Но для нашей задачи вполне достаточен.
Здравствуйте, Serginio1, Вы писали:
S>Однозначно. В Б+ деревьях очень много состояний в которое может попадать дерево.
А в твоем варианте типа мало? Все то же самое, только здесь еще о параллелизме париться не надо.
S> Вообщето весь сыр бор отсюда S>http://www.rsdn.ru/Forum/Message.aspx?mid=1824409&only=1
Здравствуйте, stalcer, Вы писали:
S>Ну да. Навигационный доступ ведь.
А зачем?
S>Второй способ вроде бы предпочтительней, так как есть кэширование и не все объекты фактически нуждаются в загрузке.
Это он на первый взгляд предпочтительней, а на второй лучше в эти дебри не лезть..
S>Но работает он почему-то гораздо медленнее.
Понятно почему. СУБД ведь не зря оптимизированы именно под последовательный доступ...
S>Так что скорость поиска по ключу имеет для меня принципиальное значение.
Ну это ты просто так ORM свой написал.
Здравствуйте, Merle, Вы писали:
M>>>Приведи мне пример задачи, где пригодился бы поиск по B+ с ключем длиннее килобайта. GZ>>Outlook. Письма, задачи e.t.c. M>Ты хорошо представляешь что такое B+? При большем размере ключа B+ уже не эффективен. M>И что ты собрался искать в письмах по ключам такого размера? M>Еще раз говорю, бля поиска в больших текстах, совсем другие механизмы нужны...
Правильно. Но если нет критерия — большое письмо и маленькое письмо, то тут у нас большой обман. Хотя бы флаг о том, что нельзя сохранять строки более 900 байт сделать нужно.
Здравствуйте, GlebZ, Вы писали:
GZ>Поэтому считаю что каждый отданный килобайт — это отданный килобайт врагу. В отличие от серверных приложений, мы обязаны ограничивать размер используемой оперативной памяти.
От оперативной памяти здесь ничего не зависит. Это все упирается в высоту B+ дерева, чем выше дерево, тем больше обращений к диску. Реально, при разнице длинны ключа больше чем в 2 раза, разница в высоте дерева будет более-менее ощутима при количестве записей подгребающих к паре миллионов, да и то, только на групповых операциях.
GZ>Что значит самая дешевая?
То и значит.
GZ>При ста маленьких таблиц? Играет.
Нет, так как при нехватке памяти нет проблем скинуть их на диск. Реально же для десктопа, будет одна-две больших таблицы и пара десятков маленьких, максимум...
GZ> Для join весьма. И именно ему надо будет вытаскивать по одному.
Не надо там по одному ничего вытаскивать. К тому моменту, когда приходится делать join по PK и этих PK много — они и так уже все в памяти отфильтрованные сидят.
Мой поинт в том, что и B+ с данной задачей справляется не плохо и поскольку от него все равно не уползти, то на первом этапе надо реализовывать только его. И только в том случае, если станет заметно, что с какими-то сценариями он не справляется, то пытаться реализовать что-то другое.
Здравствуйте, GlebZ, Вы писали:
GZ>Поэтому считаю что каждый отданный килобайт — это отданный килобайт врагу. В отличие от серверных приложений, мы обязаны ограничивать размер используемой оперативной памяти.
Но не до беспредела. У меня на машине 2гига оперативки, и я согласен если БД сожрет лишнюю сотню мег, если при этом она будет работать ощутимо быстрее.
Здравствуйте, Merle, Вы писали:
S>>Ну да. Навигационный доступ ведь. M>А зачем?
Как зачем? Потому что !
Я не говорю, то это единственный способ, запросы тоже присутствуют, но и навигационный доступ должен быть.
S>>Второй способ вроде бы предпочтительней, так как есть кэширование и не все объекты фактически нуждаются в загрузке. M>Это он на первый взгляд предпочтительней, а на второй лучше в эти дебри не лезть..
Если не лезть, то конечно. А если залезть и разобраться... Хотя бы для того чтобы разобраться.
S>>Но работает он почему-то гораздо медленнее. M>Понятно почему. СУБД ведь не зря оптимизированы именно под последовательный доступ...
Послудовательный этот как? В порядке хранения, в порядке сдедования значений в индексе или как еще?
Я бы сказал, что небольшая часть запросов подходит под эти сценарии. Джоины, например, это уже не последовательно, а как раз по ключу. Выборка по любому индексу — последовательна по отношению к этому индексу и нет — по отношению к выбираемым данным.
Ы?
S>>Так что скорость поиска по ключу имеет для меня принципиальное значение. M>Ну это ты просто так ORM свой написал.
Здравствуйте, GlebZ, Вы писали:
M>>И что ты собрался искать в письмах по ключам такого размера? M>>Еще раз говорю, бля поиска в больших текстах, совсем другие механизмы нужны... GZ>Правильно. Но если нет критерия — большое письмо и маленькое письмо, то тут у нас большой обман. Хотя бы флаг о том, что нельзя сохранять строки более 900 байт сделать нужно.
Блин! Да кто говорит, что сохранять нельзя? Храни пожалуйста, никто не мешает, хоть гигабайт — никаких проблем.
Даже индекс построить можно по первому килобайту.
Еще раз спрашиваю, что ты искать-то собрался в B+, в письмах, по ключу такого размера??
Здравствуйте, stalcer, Вы писали:
S>Я не говорю, то это единственный способ, запросы тоже присутствуют, но и навигационный доступ должен быть.
Должен, чтобы одну запись достать... А для доставания одной записи скорость не критична.
S>Если не лезть, то конечно. А если залезть и разобраться...
То понимаешь, что лучше бы не лез.
S>Послудовательный этот как? В порядке хранения, в порядке сдедования значений в индексе или как еще?
В порядке следования значений в индексе.
S>Я бы сказал, что небольшая часть запросов подходит под эти сценарии.
Как раз таких запросов подавляющее большинство, иначе бы RDBMS не удержива ли бы лидирующего положения по сию пору.
S>Джоины, например, это уже не последовательно, а как раз по ключу.
Нет, это как раз последовательно.
S>Да, собственно в том же Hibernate та же фишка .
Вот я и говорю — отстой ваш гибернейт..
Здравствуйте, Merle, Вы писали:
M>Должен, чтобы одну запись достать... А для доставания одной записи скорость не критична.
Неа, не для этого. Прежде всего для удобства. Абсолютно тоже, только более научно — для возможности написания более модульных программ со всеми вытекающими.
M>То понимаешь, что лучше бы не лез.
M>Как раз таких запросов подавляющее большинство, иначе бы RDBMS не удержива ли бы лидирующего положения по сию пору.
Спорно, так как я не согласен с твоим утверждением ниже:
S>>Джоины, например, это уже не последовательно, а как раз по ключу. M>Нет, это как раз последовательно.
select * from A left join B on B.pk = A.fk
Может по таблице A и последовательно, а по B — с поиском по ключу (UNIQUE INDEX UNIQUE SCAN), а потом еще и доступ к записи в таблице B по найденному в индексе rowid (тоже не последовательно по отношению к физическому хранению).
Что, не так скажешь?
M>Вот я и говорю — отстой ваш гибернейт..
Ну не отстой уж. Но поле для деятельности там еще огого...
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
S>>Однозначно. В Б+ деревьях очень много состояний в которое может попадать дерево. M>А в твоем варианте типа мало? Все то же самое, только здесь еще о параллелизме париться не надо.
Предлагаю тебе самому написать оба варианта. Тогда будет понятно.
Вообще вариант с описанием и алгоритмом Расширяемое хэширование есть у Бакнела хорошая кстати книга. Весь алгоритм умещается на 2-3 страницах. Почувсвуй разницу. S>> Вообщето весь сыр бор отсюда S>>http://www.rsdn.ru/Forum/Message.aspx?mid=1824409&only=1
S>>только и всего. M>Вообще-то работающий алгоритм для диска нужен не как вещь в себе, а в применении к конкретной задаче описанной здесь: Настольная БД
M>Иначе это сферический конь, в вакууме.
Некорректно потому что был поставлен вопрос " А вот работающий алгоритм для диска я пока не услышал"
дан ответ, при этом было указано, что больших бенефитов при этом не наблюдается.
А по топику, там много можно говорить. А в итоге взять какойнибудь ДБФ и лабать на нем.
Всё что нужно добавить, транзакционность не вполном объеме только для отката, внешние ключи (хотя и врукопашную можно, а то 1С ники ссылочную целостность контролируют пробегая по всей базе, правда там есть понятие неопределенного поля, но ручной контроль возможен).
И восстановление БД после критических сбоев (логи).
Этого вполне достаточно. Остальное всё можно возложить на пользовательский код, в том числе и реструктуризацию.
Опять же большое ИМХО.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, stalcer, Вы писали:
S>Неа, не для этого. Прежде всего для удобства. Абсолютно тоже, только более научно — для возможности написания более модульных программ со всеми вытекающими.
Это уже эстетика, совершенно другая категория... подвох в том, что навигационный доступ, в силу ряда объективных физических причин, не может быть быстрее последовательного, на современном техническом уровне.
S>
S>select * from A left join B on B.pk = A.fk
S>
S>Может по таблице A и последовательно, а по B — с поиском по ключу (UNIQUE INDEX UNIQUE SCAN), а потом еще и доступ к записи в таблице B по найденному в индексе rowid (тоже не последовательно по отношению к физическому хранению).
И часто тебе приходится всю таблицу B вытаскивать? В подавляющем большинстве случаев запрос выглядит как
select * from B left join A on B.pk = A.fk where B.pk = x
Вот и весь навигационный доступ.
S>Что, не так скажешь?
Сказал уже...
S>Ну не отстой уж. Но поле для деятельности там еще огого...
Отстой-отстой, как и все ORM-ы...
Здравствуйте, Merle, Вы писали:
S>>Неа, не для этого. Прежде всего для удобства. Абсолютно тоже, только более научно — для возможности написания более модульных программ со всеми вытекающими. M>Это уже эстетика, совершенно другая категория... подвох в том, что навигационный доступ, в силу ряда объективных физических причин, не может быть быстрее последовательного, на современном техническом уровне.
В чем разница Между навигационный доступ и последовательного????
Чем пробег по индексу ДБФ отличается от SQL го пробега. Чем ручная реализация будет отличаться от схемы запроса реализуемой SQL, чем будет отличаться код когда нужно прыгать по сылкам, как на родео итд. ???
Навигационный доступ для локальных БД более чем приемленный. Я им только и пользуюсь.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Вообще вариант с описанием и алгоритмом Расширяемое хэширование есть у Бакнела хорошая кстати книга. Весь алгоритм умещается на 2-3 страницах.
Со сбросом страниц на диск?
S> Некорректно потому что был поставлен вопрос " А вот работающий алгоритм для диска я пока не услышал"
Еще раз тебе говорю. Просто алгоритм для диска не интересен.
S> при этом было указано, что больших бенефитов при этом не наблюдается.
Во-во.
Здравствуйте, Serginio1, Вы писали:
S> В чем разница Между навигационный доступ и последовательного????
Тебе это надо объяснять?
S> Чем пробег по индексу ДБФ отличается от SQL го пробега. Чем ручная реализация будет отличаться от схемы запроса реализуемой SQL, чем будет отличаться код когда нужно прыгать по сылкам, как на родео итд. ???
Вот этого пассажа я вообще не понял.
S> Навигационный доступ для локальных БД более чем приемленный. Я им только и пользуюсь.
Пользуйся.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, stalcer, Вы писали:
M>Это уже эстетика, совершенно другая категория... подвох в том, что навигационный доступ, в силу ряда объективных физических причин, не может быть быстрее последовательного, на современном техническом уровне.
Это только так кажется...
В силу ряда организационных причин, таких как частое изменение программ в связи с изменениями бизнес процессов или законодательства, а также криворукость среднестатистического программиста, автоматический сбор и анализ статистики и последующее ее использование для автоматического построения запросов может привести к увеличению производительности в конечном итоге.
Причем заметь, одновременно с удобством программирования.
S>>
S>>select * from A left join B on B.pk = A.fk
S>>
M>И часто тебе приходится всю таблицу B вытаскивать?
А я здесь, всю таблицу B и не вытаскиваю. Я вытаскиваю всю таблицу A. Ну или можно не всю, добавь where на свой вкус, но только для A. Таблица B здесь — это дополнительная, связанная с основной информация, например адрес-клиента. Запрос такого вида очень распространенная вещь.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
S>> Вообще вариант с описанием и алгоритмом Расширяемое хэширование есть у Бакнела хорошая кстати книга. Весь алгоритм умещается на 2-3 страницах. M>Со сбросом страниц на диск?
Вроле Да, во всяком случае это не проблема. Но наверное погорячился на 4-5 страницах. А если честно, то я особо не разбирался. Понял алгоритм, взял на заметку, но неболее, по причине малой пригодности. Есть другие подходы, но они не для широкого использования, а под задачу. S>> Некорректно потому что был поставлен вопрос " А вот работающий алгоритм для диска я пока не услышал" M>Еще раз тебе говорю. Просто алгоритм для диска не интересен.
Ну не ты же ставил вопрос Надеюсь, что этот алгоритм был услышан S>> при этом было указано, что больших бенефитов при этом не наблюдается. M>Во-во.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
S>> В чем разница Между навигационный доступ и последовательного???? M>Тебе это надо объяснять?
Да потому, что я могу засасывать данные постранично. Навигационный доступ это доступ через курсор. Единственное его отличеие от SQL прохода по данным, в том что для него нужен буфер для копирования из считанной страницы.
Учитывая что файловая система сама кэширует файлы, то все затраты выходящие на копирование составляют гдето 400 мб/сек.
Что при проходе по 2 ГБ базе без учета вычислений, поднятия страниц иьд всего 5 сек.
А вот при проходе по индексу учитывая косвенность доступа к записи, то в процентах откомпиленный SQL запрос выигрывает очень мало.
А вот в настольной БД использование кластерного индекса вполне приемлемо. S>> Чем пробег по индексу ДБФ отличается от SQL го пробега. Чем ручная реализация будет отличаться от схемы запроса реализуемой SQL, чем будет отличаться код когда нужно прыгать по сылкам, как на родео итд. ??? M>Вот этого пассажа я вообще не понял.
S>> Навигационный доступ для локальных БД более чем приемленный. Я им только и пользуюсь. M>Пользуйся.
И на том спасибо.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, stalcer, Вы писали:
S>В силу ряда организационных причин, таких как частое изменение программ в связи с изменениями бизнес процессов или законодательства, а также криворукость среднестатистического программиста, автоматический сбор и анализ статистики и последующее ее использование для автоматического построения запросов может привести к увеличению производительности в конечном итоге. S>Причем заметь, одновременно с удобством программирования.
S>А я здесь, всю таблицу B и не вытаскиваю. Я вытаскиваю всю таблицу A. Ну или можно не всю, добавь where на свой вкус, но только для A. S> Таблица B здесь — это дополнительная, связанная с основной информация, например адрес-клиента.
Тогда ты pk и fk местами перепутал.
Здравствуйте, Serginio1, Вы писали:
S> Да потому, что я могу засасывать данные постранично.
А что толку, если у тебя данные на странице в полном беспорядке лежат?
S> Учитывая что файловая система сама кэширует файлы, то все затраты выходящие на копирование составляют гдето 400 мб/сек.
Какое копирование?
S> Что при проходе по 2 ГБ базе без учета вычислений, поднятия страниц иьд всего 5 сек.
Ты предлагаешь всю базу в память поднять?
S> А вот при проходе по индексу учитывая косвенность доступа к записи, то в процентах откомпиленный SQL запрос выигрывает очень мало.
Расскажи это разработчикам реляционных СУБД. Причем всем.
S> А вот в настольной БД использование кластерного индекса вполне приемлемо.
Очень интересно посмотреть на выгоды от использования кластерного индекса на основе хэш-таблицы.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, Serginio1, Вы писали:
S>> Да потому, что я могу засасывать данные постранично. M>А что толку, если у тебя данные на странице в полном беспорядке лежат?
Относительо индекса или по какому признаку они должны быть упорядочены???
В кластерном индесе все упорядочено.
S>> Учитывая что файловая система сама кэширует файлы, то все затраты выходящие на копирование составляют гдето 400 мб/сек. M>Какое копирование?
Копирование записи в буфер. Если при компилировании запроса проход может осуществляется по страницам напрямую, то для курсора нужно из этих страниц скопировать в буффер.
S>> Что при проходе по 2 ГБ базе без учета вычислений, поднятия страниц иьд всего 5 сек. M>Ты предлагаешь всю базу в память поднять?
Это пример если вся база закэширована. Все зависит от файловой системы и количества памяти. S>> А вот при проходе по индексу учитывая косвенность доступа к записи, то в процентах откомпиленный SQL запрос выигрывает очень мало. M>Расскажи это разработчикам реляционных СУБД. Причем всем.
Не, ты это мне скажи и докажи. А мне им нечего доказывать, т.к. выбор мой отнюдь не в их пользу, как впрочем и достаточно большого круга пользователей использующие терминальные сессии и локальные БД, и использующие все премущества навигационного доступа. На продолжительном отрезке времени. Да и тема "Настольная БД". S>> А вот в настольной БД использование кластерного индекса вполне приемлемо. M>Очень интересно посмотреть на выгоды от использования кластерного индекса на основе хэш-таблицы.
А причем здесь Хэш таблица??? Хотя ради некой истины. В чем премущество хранения данных в кластерном индексе по ПК??? От аналогичной в хэш таблице???
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Merle, Вы писали:
M>>Блин! Да кто говорит, что сохранять нельзя? Храни пожалуйста, никто не мешает, хоть гигабайт — никаких проблем. M>>Даже индекс построить можно по первому килобайту. M>>Еще раз спрашиваю, что ты искать-то собрался в B+, в письмах, по ключу такого размера??
GZ>
GZ>like '%Письмо%С уважением, Буратино%'
GZ>
Нужно регулярные выражения подключать
А зачем вообще здесь нужен индекс??? Первые символы вроде как не используются
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Ты всерьез веришь, что B+ индексы тебя спасут? В лучшем случае некоторые сервера распознают like, в котором фиксированное начало. То, что ты хочешь, называется полнотекстовый поиск, и его делают совсем совсем иначе.
Здравствуйте, GlebZ, Вы писали:
AVK>>Но не до беспредела. У меня на машине 2гига оперативки, и я согласен если БД сожрет лишнюю сотню мег, если при этом она будет работать ощутимо быстрее.
GZ>Так ты что, делаешь БД только для себя?
Нет, но у Висты рекомендуемый объем памяти 1 гиг, а для premium редакции 2 гига. Вот так вот.
GZ>У меня на машине 777 метров, загружены две студии 2005, 3 ворда, outlook, vss.
Могу только посочувствовать тому, что твое начальство не способно выделить тебе нормальное количество памяти.
GZ>Одно из бенефитов встроенной базы данных должно быть то, что ты можешь работать с массивом информации с достаточно низким потреблением оперативной памяти.
Но затачивать дизайн под это я бы не стал. Максимум — сделать это регулируемым.
Здравствуйте, Serginio1, Вы писали:
S>>> Некорректно потому что был поставлен вопрос " А вот работающий алгоритм для диска я пока не услышал" M>>Еще раз тебе говорю. Просто алгоритм для диска не интересен. S> Ну не ты же ставил вопрос
Читать надо весь топик, а не цепляться к словам. Речь шла об алгоритме, который был бы быстрее В+, а не вобще.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>>> Некорректно потому что был поставлен вопрос " А вот работающий алгоритм для диска я пока не услышал" M>>>Еще раз тебе говорю. Просто алгоритм для диска не интересен. S>> Ну не ты же ставил вопрос
AVK>Читать надо весь топик, а не цепляться к словам. Речь шла об алгоритме, который был бы быстрее В+, а не вобще.
Ну дык был показан этот самый алгоритм. Кроме того, при достижении большого размера, хэш таблица может плавно переходить в Б+ дерево, получая нужную универсальность. На самом деле переходных алгоритмов хорошо работающих в определенных диапозонах достаточно много, униврсальные не всегда быстры и свежи.
На самом деле я не цепляюсь. Честно. Но сам алгоритм Extendible Hashing мне лично очень нравится.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Относительо индекса или по какому признаку они должны быть упорядочены???
Ключи индекса должны быть упорядочены.
S> В кластерном индесе все упорядочено.
Как упорядочены — у тебя же хэш, а он порядка не гарантирует.
S> Это пример если вся база закэширована. Все зависит от файловой системы и количества памяти.
Ну-ну..
S> Не, ты это мне скажи и докажи.
Зачем? Я и так уже устал мыслью по древу растекаться...
S> А причем здесь Хэш таблица???
Ну ты же ее использование отстаиваешь... Или уже передумал?
S> В чем премущество хранения данных в кластерном индексе по ПК???
Кластерный индекс по PK создается в очень редких случаях.
Здравствуйте, Serginio1, Вы писали:
AVK>>Читать надо весь топик, а не цепляться к словам. Речь шла об алгоритме, который был бы быстрее В+, а не вобще. S> Ну дык был показан этот самый алгоритм.
Ничего там не было показано. Был показан алгоритм, который, как мне кажется, как минимум не лучше В+, если не хуже.
S> Кроме того, при достижении большого размера, хэш таблица может плавно переходить в Б+ дерево, получая нужную универсальность.
Плавно не получится, слишком дорого обходится перестройка.
S> На самом деле я не цепляюсь. Честно. Но сам алгоритм Extendible Hashing мне лично очень нравится.
Мне тоже, когда речь идет об объемах, которые не сложно уместить в памяти, либо когда данные не меняются.
Здравствуйте, Merle, Вы писали:
S>> А вот в настольной БД использование кластерного индекса вполне приемлемо. M>Очень интересно посмотреть на выгоды от использования кластерного индекса на основе хэш-таблицы.
Очень интересно посмотреть на выгоды от использования кластерного индекса на основе guid.
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, GlebZ, Вы писали:
GZ>>Здравствуйте, Merle, Вы писали:
M>>>Блин! Да кто говорит, что сохранять нельзя? Храни пожалуйста, никто не мешает, хоть гигабайт — никаких проблем. M>>>Даже индекс построить можно по первому килобайту. M>>>Еще раз спрашиваю, что ты искать-то собрался в B+, в письмах, по ключу такого размера??
GZ>>
GZ>>like '%Письмо%С уважением, Буратино%'
GZ>>
S> Нужно регулярные выражения подключать S> А зачем вообще здесь нужен индекс??? Первые символы вроде как не используются
Обломс. Согласен. Буду жрать крокодилов и пить уксус.
Здравствуйте, AndrewVK, Вы писали:
AVK>Ты всерьез веришь, что B+ индексы тебя спасут? В лучшем случае некоторые сервера распознают like, в котором фиксированное начало. То, что ты хочешь, называется полнотекстовый поиск, и его делают совсем совсем иначе.
Да я то вполне понимаю(и про ошибочку с like понимаю ). Но наверняка начнутся привязки системы поиск к несвойственным ему полям. Другого пути то нет. Есть поле comments, в который кладут некоторый коментарий. И захотелось программеру сделать по нему поиск. Обычно комментс в районе 200-300 байт(если не null), но один коммент — 2000 кила. Ошибка вывалится то у пользователя, и что делать? Какой нибудь рычаг о том, что структура выходит за пределы индекса нужен. Пуская программер обрабатывает его по своему усмотрению. Но он нужен.
Здравствуйте, AndrewVK, Вы писали:
GZ>>Одно из бенефитов встроенной базы данных должно быть то, что ты можешь работать с массивом информации с достаточно низким потреблением оперативной памяти.
AVK>Но затачивать дизайн под это я бы не стал. Максимум — сделать это регулируемым.
Обязательно. Но при слишком маленьком кэше быстродействие может пострадать. И возможно (пока только подозрения) эта зависимость может быть экспотенциальной.
Здравствуйте, stalcer, Вы писали: S>Кстати, когда СУБД делает хеш-джоин, она ведь строит хэш, то есть где-то его хранит. А если он в память не помещается?
Спулит на диск, естеснно.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Читать надо весь топик, а не цепляться к словам. Речь шла об алгоритме, который был бы быстрее В+, а не вобще. S>> Ну дык был показан этот самый алгоритм.
AVK>Ничего там не было показано. Был показан алгоритм, который, как мне кажется, как минимум не лучше В+, если не хуже.
S>> Кроме того, при достижении большого размера, хэш таблица может плавно переходить в Б+ дерево, получая нужную универсальность.
AVK>Плавно не получится, слишком дорого обходится перестройка.
Смотря на каких объемах. Отключение индекса при масштабных вставках нормальная практика, а эффект от построения индекса с 0 достаточный. S>> На самом деле я не цепляюсь. Честно. Но сам алгоритм Extendible Hashing мне лично очень нравится.
AVK>Мне тоже, когда речь идет об объемах, которые не сложно уместить в памяти, либо когда данные не меняются.
Так скажем меняются, но в определенном диапозоне и память нужна только для ~ 1/1024 (1 узел на страницу) от всего объема данных то это не проблема. Перестроение страниц индекса при переполнении не приводят же в ужас.
Нужно реально щупать бенефиты. Но скорее всего они не будут впечатляющими, а поэтому данный алгоритм мало пригодный, интересен в основном с теоритической точки.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
S>> В чем премущество хранения данных в кластерном индексе по ПК??? M>Кластерный индекс по PK создается в очень редких случаях.
Использование Такой Хэш таблицы только как быстрого поиска по хэшу первичного ключа. Словарь одним словом.
Там упорядочивание не нужно.
Ключи для подчиненных таблиц это другая песня.
Ладно не туда я влез. Прошу прощения.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, stalcer, Вы писали: S>>Кстати, когда СУБД делает хеш-джоин, она ведь строит хэш, то есть где-то его хранит. А если он в память не помещается? S>Спулит на диск, естеснно.
Зачем?
Здравствуйте, Serginio1, Вы писали:
S> Смотря на каких объемах.
На больших. А на маленьких В+ практически идентичен хеш-таблице.
S> Отключение индекса при масштабных вставках нормальная практика,
Масштабные вставки нечастая операция. Куда чаще бывают единичные вставки, но следующие с маленьким интервалом. Перестройка хеша при переполнении приведет к резкому увеличению времени отклика.
AVK>>Мне тоже, когда речь идет об объемах, которые не сложно уместить в памяти, либо когда данные не меняются. S> Так скажем меняются, но в определенном диапозоне и память нужна только для ~ 1/1024 (1 узел на страницу) от всего объема данных то это не проблема.
Извини конечно, но спорить с человеком, игнорирующим логику, тяжело. Попробуй объяснить, как связана твоя и моя фраза. Я не смог.
Здравствуйте, GlebZ, Вы писали:
GZ>Очень интересно посмотреть на выгоды от использования кластерного индекса на основе guid.
А кто сказал, что я собираюсь использовать кластерный индекс на основе GUID? Это Serginio собирается его для хэшей использовать, вот я и спросил зачем...
Кстати, по GUID он бы пригодился, в случае если GUID FK, а не PK...
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, GlebZ, Вы писали:
GZ>>Поэтому считаю что каждый отданный килобайт — это отданный килобайт врагу. В отличие от серверных приложений, мы обязаны ограничивать размер используемой оперативной памяти. M>От оперативной памяти здесь ничего не зависит. Это все упирается в высоту B+ дерева, чем выше дерево, тем больше обращений к диску. Реально, при разнице длинны ключа больше чем в 2 раза, разница в высоте дерева будет более-менее ощутима при количестве записей подгребающих к паре миллионов, да и то, только на групповых операциях.
Давай все таки разберем нагрузку как это делает оптимизатор. Нагрузка на хард, нагрузка на проц, нагрузка на память. Нагрузка на проц меньше чем в случае с B+. Нагрузка на память также меньше. Нагрузка на диск меньше. Так чем он хуже чем B+?
GZ>>При ста маленьких таблиц? Играет. M>Нет, так как при нехватке памяти нет проблем скинуть их на диск. Реально же для десктопа, будет одна-две больших таблицы и пара десятков маленьких, максимум...
Абсолютно согласен. Но опять подумаем, у нас есть две таблицы, одна на миллион, вторая на 1000. Нам нужно будет сделать миллион сравнений. Какая будет разница между хеш-таблицей и B+ учитывая, что хеш-таблица не требует сравнений значений.
И еще, какая разница будет в производительности, если Андрей будет в основном использовать keyset курсоры.
Здравствуйте, AndrewVK, Вы писали:
AVK>И это все равно будет полнотекстовый поиск, со всеми вытекающими.
Да, но у тебя есть бесплатные инструменты полнотекстового поиска на твоей базе?
Здравствуйте, GlebZ, Вы писали:
AVK>>И это все равно будет полнотекстовый поиск, со всеми вытекающими. GZ>Да, но у тебя есть бесплатные инструменты полнотекстового поиска на твоей базе?
Нету. Но эту проблему надо решать отдельно, там совсем другие алгоритмы.
Здравствуйте, GlebZ, Вы писали:
GZ>Давай все таки разберем нагрузку как это делает оптимизатор. Нагрузка на хард, нагрузка на проц, нагрузка на память. Нагрузка на проц меньше чем в случае с B+. Нагрузка на память также меньше. Нагрузка на диск меньше.
Это все вилами по воде писано. Ту разве что тесты что то покажут.
GZ>И еще, какая разница будет в производительности, если Андрей будет в основном использовать keyset курсоры.
Здравствуйте, GlebZ, Вы писали:
GZ> Нагрузка на проц меньше чем в случае с B+. Нагрузка на память также меньше. Нагрузка на диск меньше. Так чем он хуже чем B+?
Нагрузка на проц меньше, нагрузка на память — больше, нагрузка на диск +/- такая же...
Она может быть даже и не хуже, но и не настолько лучше, чтобы заморачиваться с созданием и поддержкой еще одного типа индексов.
GZ> Какая будет разница между хеш-таблицей и B+ учитывая, что хеш-таблица не требует сравнений значений.
А ты всеь миллион в памяти будешь деражать? Вот и вылезет в итоге, что если B+ проигрывает, то не на много...
Здравствуйте, AndrewVK, Вы писали:
AVK>Извини конечно, но спорить с человеком, игнорирующим логику, тяжело. Попробуй объяснить, как связана твоя и моя фраза. Я не смог.
А мы разве спорим??? Просто не ты ни я не видим смысла в этой хэш таблице, но ты её отвергаешь, мне интересна как теоретическая разработка.
А понятия ("об объемах, которые не сложно уместить в памяти, либо когда данные не меняются")
Понятия растяжимые. Опять же перестройке подвергается не вся хэш таблица. Ладно пусть будет у меня плохо с логикой.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Что бы замять этот разговор то в зависимости от строение бд можно придумать строение ПК так, чтобы по нему можно было найти физический адрес. Например номер записи, по которой можно найти требуемую страницу итд. Если не требуется репликация то можно его совмещать и ИД БД.
Но это так фантазии, но не безнадёжные. некий RID
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Sinclair, Вы писали:
GZ>В Oracle если в like указана любая строка не начинающаяся с символа маски, то у нее есть полное право испольняться через индекс.
В MS SQL, afaik, тоже. НУ И ЧТО? Строка, не начинающаяся с маски, приводит опять же к расщеплению предиката. Ничего не меняется.
Я не понимаю, в чем проблема? Ты уже понял, что ограничение на длину ключа НЕ ПРИВОДИТ к ошибкам? Оно просто приводит к переключению на более дорогостоящие алгоритмы в некоторых особо неудачных случаях.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>Что бы замять этот разговор то в зависимости от строение бд можно придумать строение ПК так, чтобы по нему можно было найти физический адрес.
AVK>Нельзя, потому что физический адрес меняется при расщеплении страницы и придется все FK в базе отыскивать и править.
Может я чего не понимаю. ПК отвечает за быстрый поиск физического адреса в БД он неизменяем.
При этом он может сосуществовать совместно и с обычным ПК в Б+ дереве. Запись неподвижна внутри страницы. Как правило например в фокспро это так если конечно не делать упакоку, новые записи становятся на место удаленных (правда там индекс, но вполе можно использовать спписки).
Все зависит от организации БД. Там где БД ветвистая с большим количеством ссылок, такой подход оправдан.
При разного рода усечениях, легче переписать БД реструкуризовав её. Понимаю, что это утопия.
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Merle, Вы писали:
M>При этом у тебя в модели ошибочка по логике вещей должно быть:
А для демонтрации моих мыслей должно быть так как у меня было!
M>Так как адресов у клиента вполне может быть несколько.... И вся основная нагрузка ложится на аккуратно упорядоченный FK.
Блиииин , нафига ты изменил мою модель классов. Это же пример. Для изначальной модели и БД будет как раз как надо.
Мы же говорим про навигационный доступ. В первую очередь про "много-ко-одному" ассоциации, то есть ссылки, а не коллекции. Я же не отрицаю, что коллекции тоже бывают, но проблема то затронутая мной — она с одиночными ссылками. Так что их и обсуждать надо.
PS: длина ветки уже существенно превысила ее значимость.
Здравствуйте, Serginio1, Вы писали:
S> При этом он может сосуществовать совместно и с обычным ПК в Б+ дереве. Запись неподвижна внутри страницы.
В случае если это записи в сортированной по индексу(с кластеризованным индексом) таблице, то при балансировке дерева записи перемещаются.
Здравствуйте, stalcer, Вы писали:
S>А для демонтрации моих мыслей должно быть так как у меня было!
Понимаешь, за всю свою практику я не разу не встречался с такими задачами, как у тебя в мыслях..
S>Блиииин , нафига ты изменил мою модель классов. Это же пример.
Значит надо было выбрать более удачный пример...
S> Для изначальной модели и БД будет как раз как надо.
Нет, будет как ненадо. В подавляющем большинстве практически применимых случаев по PK выбирается уникальная запись и далее идет выборка по FK из дочерних таблиц, классический пример Order/Detail.
S>Мы же говорим про навигационный доступ.
Мы говорим про то, какой тип доступа наиболее распространен в реальных приложениях, навигационный или не очень.
S>Я же не отрицаю, что коллекции тоже бывают, но проблема то затронутая мной — она с одиночными ссылками. Так что их и обсуждать надо.
Это твоя проблема, а не та, которую мы обсуждаем. Если твоя задача именно такова как ты описываешь (в чем я честно говоря сомневаюсь), то скорее всего тебе больше подойдут ООБД, а не реляционные.
Здравствуйте, Merle, Вы писали:
M>Здравствуйте, stalcer, Вы писали:
S>>А для демонтрации моих мыслей должно быть так как у меня было! M>Понимаешь, за всю свою практику я не разу не встречался с такими задачами, как у тебя в мыслях..
Странно. Обычная ситуация когда надо показать список чего-нибудь. Список сотрудников, например, показать в сетке с дополнительными колонками: город, в котором он живет, отдел в котором работает, имя руководителя, которому подчиняется и т.п.
Тоже для отчетов.
M>В подавляющем большинстве практически применимых случаев по PK выбирается уникальная запись и далее идет выборка по FK из дочерних таблиц, классический пример Order/Detail.
Это если ты хочешь показать на форме детально одну сущность. А если отчет или форма со списком, то все наоборот.
M>Мы говорим про то, какой тип доступа наиболее распространен в реальных приложениях, навигационный или не очень.
Здесь существенная оговорка: в реальных приложениях, написанных как ты привык, и теми средствами, к которым ты привык.
А вот ты посмотри на просто приложения, без баз данных, там навигационного доступа значительно больше. А почему? А потому что это удобней и естественней.
А мы кстати обсуждаем настольные базы данных, в которых технические проблемы организации навигационного доступа совсем не такие, как в сетевой многопользовательской СУБД.
Здравствуйте, stalcer, Вы писали:
S>Странно. Обычная ситуация когда надо показать список чего-нибудь. Список сотрудников, например, показать в сетке с дополнительными колонками: город, в котором он живет, отдел в котором работает, имя руководителя, которому подчиняется и т.п.
Ты же показываешь не весь список сотрудников, а список сотрудников принадлежащих к какому-либо отделу... Вот и поехали, ID-отдела — FK в списке сотрудников.
И так всегда. Если записей мало, то скорость навигационного доступа не критична, если их много, то записи начинают фильтровать, причем, что характерно, последовательно.
S>Это если ты хочешь показать на форме детально одну сущность. А если отчет или форма со списком, то все наоборот.
Ничего не наоборот, все тоже самое.
S>А вот ты посмотри на просто приложения, без баз данных, там навигационного доступа значительно больше.
Ничего подобного, то что ты принимаешь за навигационный доступ все равно реализуется через коллекции в том или ином виде.
S>А почему? А потому что это удобней и естественней. Это не вопрос удобства. Все упирается в то, знаешь ли ты идентификатор конкретного объекта или нет, если знаешь то за одним объектом лучше, конечно обратиться напрямую, а вот если нет (а в болшинстве случаев это так), то через групповые операции и вот они-то как раз самые критичные, потому как их много и они существенно дороже.
S>А мы кстати обсуждаем настольные базы данных, в которых технические проблемы организации навигационного доступа совсем не такие, как в сетевой многопользовательской СУБД.
Все многопользовательские приложения вырасли из настольных и проблемы и паттерны доступа там, в седнем, те же самые.
Пойми, если бы доступ был преимущественно навигационный, мы бы все уже давно бы сидели на ООБД и горя бы не знали, и никогда бы не слышали про реляционную теорию и прочую заумь, а ностальгировали бы по сетевым БД.
S>Здесь существенная оговорка: в реальных приложениях, написанных как ты привык, и теми средствами, к которым ты привык. S>А вот ты посмотри на просто приложения, без баз данных, там навигационного доступа значительно больше. А почему? А потому что это удобней и естественней.
Нет, не поэтому. А потому, что в императивных языках программирования средства ассоциативного доступа отсутствуют. Точка. А средства навигационного доступа встроены прямо аж на уровне ассемблера.
В итоге программист специально вводит навигационные решения для задач ассоциативного доступа. Ну вот типа сначала ему надо ассоциировать адрес с юзером, и он заводит в юзере указатель на адрес. Потом ему надо заниматься поиском юзеров по адресу, и он сначала делает поиск в списке адресов, потом приделывает к списку адресов хештаблицу "текст адреса"->адрес, потом делает сканирование коллекции юзеров в поисках ссылающихся на данный адрес, потом он думает, что это неэффективно, и вводит бимэп userID<->addressId... И все только от того, что нету у него встроенных средств записать select * from users where address.city = @city.
В большинстве случаев ассоциативный доступ удобнее. S>А мы кстати обсуждаем настольные базы данных, в которых технические проблемы организации навигационного доступа совсем не такие, как в сетевой многопользовательской СУБД.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Merle, Вы писали:
S>>Странно. Обычная ситуация когда надо показать список чего-нибудь. Список сотрудников, например, показать в сетке с дополнительными колонками: город, в котором он живет, отдел в котором работает, имя руководителя, которому подчиняется и т.п. M>Ты же показываешь не весь список сотрудников, а список сотрудников принадлежащих к какому-либо отделу...
Ты хоть прочитай, что я показываю. Я показываю список сотрудников (неважно по какому критерию отфильтрованный) и вместе с ним НЕСКОЛЬКО дополнительных колонкок в сетке — отдел, город и т.п. Если бы я показывал сотрудников одного отдела, то нафига мне дополнительная колонка в сетке показывающая этот (и так известный) отдел.
M>Ничего подобного, то что ты принимаешь за навигационный доступ все равно реализуется через коллекции в том или ином виде.
Да не все делается через коллекции. В этом-то и фишка. Есть и коллекции и одиночные ссылки. Все тот-же пример:
int P()
{
int res = 0;
foreach (auto i in (from Clients where ...))
res += M(i);
return res;
}
int M(Client client)
{
if (client.address.street = 'блабла')
return 1;
return 0;
}
А вот теперь представь, что метод M() содержит сложную логику с вызовом виртуальных методов и т.п. и вообще половину ее писал не ты. И эти методы обращаются то по одной ссылке, то по другой, а может и глубже, чем одна ссылка. Ну и как ты в этом случае сформируешь запрос который сразу подгрузит все необходимые данные.
Еще раз, пусть логика сложная! В запросе не отразить!
M>Все многопользовательские приложения вырасли из настольных и проблемы и паттерны доступа там, в седнем, те же самые.
Тогда и нефиг было начинать обсуждение особенностей настольных СУБД.
M>Пойми, если бы доступ был преимущественно навигационный, мы бы все уже давно бы сидели на ООБД и горя бы не знали, и никогда бы не слышали про реляционную теорию и прочую заумь, а ностальгировали бы по сетевым БД.
А не сидим то не потому что не хотим, а из-за технических проблем реализации.
А групповой доступ, как ты говоришь, действительно имеет место, но есть один ньюанс: SQL, при помощи которого ты собираешься этот доступ обеспечивать настолько убог, что не позволяет выразить более менее сложной логики. Вот если бы можно было функции основного языка в запросы вставлять, тогда да.
Да только такой движок сам по себе для выполнения запросов стал бы активно использовать доступ по ключу и т.п. Так что в сущности — одно и тоже.
А так получается большуууущий геморроище: сначала забей на модульность и инкапсуляцию и грузи данные в одном запросе, повторяя часть логики (которая уже прописана и в методах) в запросе. Но это еще не самое страшное. Самое страшное это то, что когда сложность логики возрастет, то уж будь любезен перепиши половину, нафиг, на хранимых процедурах. А когда еще возрастет — тогда уже можешь наслаждаться писанием на основном языке и инкапсуляцией и т.п.
Здравствуйте, Sinclair, Вы писали:
S>В большинстве случаев ассоциативный доступ удобнее.
Ну хорошо. Давай обсудим этот вариант. Ассоциативный доступ будет реально удобней, только если есть возможность вставлять любые выражения основного языка во where. Включая функции (виртуальные). Только тогда весь оптимизатор запросов и исполнитель необходимо будет перенести на клиент (апп-сервер). Да и индексы (типа той хэш-таблицы из твоего примера) тоже.
Но проблема-то в том, что логика не может писаться, чтобы быть одновременно эффективной как для императивного исполнения так и для использования в оптимизаторе запросов. Вследствие чего оптимизатор курит в сторонке и мы почти что имеем полный перебор. А самое главное, что поведение системы становиться непредстказуемым: до изменения логики оптимизатор хорошо работал, а после небольшого изменения — вырубился.
Здравствуйте, stalcer, Вы писали:
S>Ты хоть прочитай, что я показываю.
Я читаю, и читаю я, что ты все время какие-то искуственные задачи приводишь...
S>Я показываю список сотрудников (неважно по какому критерию отфильтрованный)
Важно. Важно что этот список сотрудников отфильтрованый, а следовательно все его PK уже подгружены и по этим PK ты выбираешь список дочерних элементов, связаных по FK, причем этих дочерних элементов как правило больше одного.
S>Да не все делается через коллекции. В этом-то и фишка. Есть и коллекции и одиночные ссылки. Все тот-же пример:
Фишка в том, что не все, но большинство. Причем одна навигационная операция — не проблема, а вот с коллекциями надо работать наиболее оптимальным образом.
S>А вот теперь представь, что метод M() содержит сложную логику с вызовом виртуальных методов и т.п. и вообще половину ее писал не ты.
Тогда это проблемы метода M, и за такую архитектуру к компу не подпускать..
S> Ну и как ты в этом случае сформируешь запрос который сразу подгрузит все необходимые данные.
Так и сформировать. В конечном итоге — это данные, которые подгружаются по опредедленному предикату, значит надо родить этот предикат.
S>Еще раз, пусть логика сложная! В запросе не отразить!
Так не бывает. Запрос не предназначен для отражения логики, логикой пусть ОО занимается и задача этой логики сформировать подходящий фильтр для SQL. Все.
S>Тогда и нефиг было начинать обсуждение особенностей настольных СУБД.
Ну во-первых это не ко мне, во-вторых у настольных есть другие особенности, но с паттерном доступа они мало связаны.
Если бы затык был в навигации, то надо было бы писать ООБД, а не реляционку.
S>А не сидим то не потому что не хотим, а из-за технических проблем реализации.
Так что же это за такие технические проблемы, если навигационный доступ такой замечательный?
S>А групповой доступ, как ты говоришь, действительно имеет место, но есть один ньюанс: SQL, при помощи которого ты собираешься этот доступ обеспечивать настолько убог, что не позволяет выразить более менее сложной логики.
SQL не убог, он просто не предназначен для реализации логики — это не его задача.
Сосредоточься и отдели у себя в голове данные от объектов, навигационный доступ удобен для объектов, а не для данных, с данными все наоборот. Как только отделить одно от другого, все сразу станет на свои места, не надо заставлять данные думать.
S>Вот если бы можно было функции основного языка в запросы вставлять, тогда да.
Такой есть SQLJ, например.
S>Да только такой движок сам по себе для выполнения запросов стал бы активно использовать доступ по ключу и т.п. Так что в сущности — одно и тоже.
Ничего подобного, лучше SQL-я для работы с данными пока что ничего нет, не смотря на все потуги и никакого доступа по ключу не намечается.
Еще раз тебе говорю, перестань обращаться с данными как с объектами, ни к чему хорошему это не приведет.
S>А так получается большуууущий геморроище:
Это все от неумения готовить..
Здравствуйте, Sinclair, Вы писали:
S>Нет, не поэтому. А потому, что в императивных языках программирования средства ассоциативного доступа отсутствуют. Точка. А средства навигационного доступа встроены прямо аж на уровне ассемблера. S>В итоге программист специально вводит навигационные решения для задач ассоциативного доступа. Ну вот типа сначала ему надо ассоциировать адрес с юзером, и он заводит в юзере указатель на адрес. Потом ему надо заниматься поиском юзеров по адресу, и он сначала делает поиск в списке адресов, потом приделывает к списку адресов хештаблицу "текст адреса"->адрес, потом делает сканирование коллекции юзеров в поисках ссылающихся на данный адрес, потом он думает, что это неэффективно, и вводит бимэп userID<->addressId... И все только от того, что нету у него встроенных средств записать select * from users where address.city = @city.
Извиняюсь, не могу сдержаться.
Во первых ты говоришь не о доступе как таковом, а о поиске. Что является лишь частью доступа. Во вторых, всех так на курсоры тянем что у меня есть сомнения в декларативном доступе. А тянет всех потому как нельзя в sql запросе указывать сложную логику зависящую от состояния читаемого объекта(даешь в sql делегаты, хотя и они могут не спасать). В третьих, sql так построен, что дальше навигации с курсором особо не уйдешь. В пятых, у меня как бич получается, что на каждом проекте мне приходится в той. или иной мере реализовывать редактор sql запросов. В шестых, весьма удобно отойти от отношения как такового, а перейти к навигации в определенных случаях. Например у тебя форма. Обычно данные в такой форме есть дерево по которому в случае навигационного доступа было бы удобно бегать. S>В большинстве случаев ассоциативный доступ удобнее.
В большинстве случаев удобнее оба варианта в смешанном состоянии. S>>А мы кстати обсуждаем настольные базы данных, в которых технические проблемы организации навигационного доступа совсем не такие, как в сетевой многопользовательской СУБД.
Ага, там единственная проблема, она не sql, и под sql никак не клеится.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Serginio1, Вы писали:
S>> При этом он может сосуществовать совместно и с обычным ПК в Б+ дереве. Запись неподвижна внутри страницы. GZ>В случае если это записи в сортированной по индексу(с кластеризованным индексом) таблице, то при балансировке дерева записи перемещаются.
Разумеется это некасается кластерного индекса. Кроме того никто не зпрещает иметь две таблицы обычную и кластерную для для более быстрого поиска и чесе по диапозону индекса. При ЭТОМ ССылка на элемент может состоять из двух записей и применяться либо Б+ дерево либо прямая (на самом деле косвенная но с бытрым поиском нужной страницы RID). Излищняя избыточность но более быстрый переход по ссылке.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>>> При этом он может сосуществовать совместно и с обычным ПК в Б+ дереве. Запись неподвижна внутри страницы. GZ>>В случае если это записи в сортированной по индексу(с кластеризованным индексом) таблице, то при балансировке дерева записи перемещаются. S>Разумеется это некасается кластерного индекса.
Нет не только кластерного. В случае если у нас запись имеет поле с изменяемой длиной, то при расширении запись может уже не помещаться на текущей таблице, и как результат его нужно будет переносить на другую страницу. И тогда все индексы нужно обновлять. S>Излищняя избыточность но более быстрый переход по ссылке.
Почти соглашусь. Однако у нас получатся еще и другие накладные расходы(одно то, что нам придется постоянно добывать типизированные объекты из byte[] чего-то стоят). Как бы при этих накладных расходах разность в работе этих фич не стремились к нулю. Поэтому максимум чем можно так абстрактно(но более точно) измерять — количество чтений-записей.
Но косвенность любого индекса — это ключевое слово.
> Хотелось бы обсудить как могла бы выглядеть современная настольная СУБД с учетом сужения класса решаемых задач и использования новых технологий и подходов.
С ростом мощи машин следует признать, что лучшей универсальной настольной БД д.б. признан[а|о] Windows Registry. Реестр, в общем.
Посудите сами:
>1) in process или out of process?
Неважно
>2) Физическая структура хранения на диске — алгоритмы, разбиение на файлы etc
Неважно
>3) Описание метаданных
Полагаю, что для домашней БД важен принцип KISS. оставим метаданные ораклу.
>4) Способ формирования запросов
На усмотрение программиста.
И не забывайте, что любое дерево легко разворачивается в таблицы!
>5) Контроль на уровне БД. Вобще разграничение функций между движком БД и прикладным кодом
Если нужен контроль — пишется обёртка. Хоть бы и SQL реализующая, во!
Зато есть встроенный контроль доступа из коробки! Интегрированный с системой безопасности Windows!
>6) Алгоримты деплоймента
Стандартизованные де-факто *.reg файлы для бэкапа и переноса данных!
Движок уже предустановлен на всех Windows, включая мобильные!
Здравствуйте, Dimentiy, Вы писали:
D>Если нужен контроль — пишется обёртка. Хоть бы и SQL реализующая, во! D>Зато есть встроенный контроль доступа из коробки! Интегрированный с системой безопасности Windows!
>>6) Алгоримты деплоймента
D>Стандартизованные де-факто *.reg файлы для бэкапа и переноса данных! D>Движок уже предустановлен на всех Windows, включая мобильные!
D>Все на использование реестра! D>
На Symbian что делать?
Уж лучше свой XML-движок БД написать.
Здравствуйте, Merle, Вы писали:
M>Важно. Важно что этот список сотрудников отфильтрованый, а следовательно все его PK уже подгружены и по этим PK ты выбираешь список дочерних элементов, связаных по FK, причем этих дочерних элементов как правило больше одного.
Я не описываю случай "мастер-деталь". НЕ ОПИСЫВАЮ! Если ты хочешь поговорить об этом — заведи отдельную ветку. Мой пример о другом. И нефиг переводить стрелки .
S>>А вот теперь представь, что метод M() содержит сложную логику с вызовом виртуальных методов и т.п. и вообще половину ее писал не ты. M>Тогда это проблемы метода M, и за такую архитектуру к компу не подпускать..
M>Так и сформировать. В конечном итоге — это данные, которые подгружаются по опредедленному предикату, значит надо родить этот предикат.
В конечном итоге любая программа — это машинные коды. И значит надо просто правильно написать их !
Только почему же никто так не делает, а?
M>Так не бывает. Запрос не предназначен для отражения логики, логикой пусть ОО занимается и задача этой логики сформировать подходящий фильтр для SQL. Все.
Да ну. Вот такие запросы, которые как ты говоришь, не предназначены для работы с логикой, ты же сам называешь естественными. Когда ты искусственно разбиваешь модель прикладной программы на данные и объекты — это уже совсем не естественно.
Естественный ассоциативный доступ — это запросы к объектному представлению с использованием логики. Запросы к "данным" да еще и без логики — не естественны. И навигационный доступ намного более естественный ем такие запросы. О чем я и говорил .
M>..., во-вторых у настольных есть другие особенности, но с паттерном доступа они мало связаны.
С паттерном доступа они как раз хорошо связаны. Внутри обычной СУБД в планах выполнения запросов часто встречается UNIQUE INDEX UNIQUE SCAN, что есть суть доступ по ключу. Однако это внутри! Так как между клиентом и сервером — сеть и толстый API. А для настольной СУБД — запросто можно вынести и наружу, таким образом получив фактически быстрый навигационный доступ.
M>Сосредоточься и отдели у себя в голове данные от объектов, навигационный доступ удобен для объектов, а не для данных, с данными все наоборот. Как только отделить одно от другого, все сразу станет на свои места, не надо заставлять данные думать.
А зачем мне десять разных представлений модели прикладной области? Да еще и разных по смыслу, как ты тут заявляешь.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Serginio1, Вы писали:
S>>>> При этом он может сосуществовать совместно и с обычным ПК в Б+ дереве. Запись неподвижна внутри страницы. GZ>>>В случае если это записи в сортированной по индексу(с кластеризованным индексом) таблице, то при балансировке дерева записи перемещаются. S>>Разумеется это некасается кластерного индекса. GZ>Нет не только кластерного. В случае если у нас запись имеет поле с изменяемой длиной, то при расширении запись может уже не помещаться на текущей таблице, и как результат его нужно будет переносить на другую страницу. И тогда все индексы нужно обновлять. S>>Излищняя избыточность но более быстрый переход по ссылке. GZ>Почти соглашусь. Однако у нас получатся еще и другие накладные расходы(одно то, что нам придется постоянно добывать типизированные объекты из byte[] чего-то стоят). Как бы при этих накладных расходах разность в работе этих фич не стремились к нулю. Поэтому максимум чем можно так абстрактно(но более точно) измерять — количество чтений-записей.
ну получить тип по &byte[0] не проблема, просто ссылка на структуру. Но про указатели мы не забываем. То бишь ничего не стоит. Практика это доказывает. В нативе вообще проще т.к. просто копирование в типизированный буффер (структуру). GZ>Но косвенность любого индекса — это ключевое слово.
Разные уровни этой коственности. Например в фокспро для увеличения емкости ключи хранятся запакованными (логично для сортированных строк).
Итд. При этом прямая ссылка более подходящий способ хранения в объекие, чем хранения ссылки через промежуточный объект
и солнце б утром не вставало, когда бы не было меня
S>>>>> При этом он может сосуществовать совместно и с обычным ПК в Б+ дереве. Запись неподвижна внутри страницы. GZ>>>>В случае если это записи в сортированной по индексу(с кластеризованным индексом) таблице, то при балансировке дерева записи перемещаются. S>>>Разумеется это некасается кластерного индекса. GZ>>Нет не только кластерного. В случае если у нас запись имеет поле с изменяемой длиной, то при расширении запись может уже не помещаться на текущей таблице, и как результат его нужно будет переносить на другую страницу. И тогда все индексы нужно обновлять. S>>>Излищняя избыточность но более быстрый переход по ссылке. GZ>>Почти соглашусь. Однако у нас получатся еще и другие накладные расходы(одно то, что нам придется постоянно добывать типизированные объекты из byte[] чего-то стоят). Как бы при этих накладных расходах разность в работе этих фич не стремились к нулю. Поэтому максимум чем можно так абстрактно(но более точно) измерять — количество чтений-записей.
Нужно отметить еще то, что при этом ты получаешь большую гибкость приеняя к объектам все тодступныеме методы для работы с ними (регулярные выражения,CSV для строк итд) Даже тупо потери при нормальной сериализации достаточно малы, учитывая получаемые бенефиты. S> ну получить тип по &byte[0] не проблема, просто ссылка на структуру. Но про указатели мы не забываем. То бишь ничего не стоит. Практика это доказывает. В нативе вообще проще т.к. просто копирование в типизированный буффер (структуру). GZ>>Но косвенность любого индекса — это ключевое слово. S> Разные уровни этой коственности. Например в фокспро для увеличения емкости ключи хранятся запакованными (логично для сортированных строк). S>Итд. При этом прямая ссылка более подходящий способ хранения в объекие, чем хранения ссылки через промежуточный объект
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, stalcer, Вы писали:
S>Я не описываю случай "мастер-деталь". НЕ ОПИСЫВАЮ! Если ты хочешь поговорить об этом — заведи отдельную ветку. Мой пример о другом. И нефиг переводить стрелки .
Значит варианта два. Либо твоя задача — большое исключение и не для реляционных БД, либо ты ее неправильно описываешь, поскольку 99% задач сводятся к master/detail...
S>В конечном итоге любая программа — это машинные коды. И значит надо просто правильно написать их ! S>Только почему же никто так не делает, а?
Почему не делают? Делают.
S>Да ну. Вот такие запросы, которые как ты говоришь, не предназначены для работы с логикой, ты же сам называешь естественными. Когда ты искусственно разбиваешь модель прикладной программы на данные и объекты — это уже совсем не естественно.
Вот это как раз естественно, потому что с данными надо работать одним способом, а с объектами — другим. Потому что данные — это просто голая информация, а объект — в первую очередь поведение, и если мешать все это в кучу, то ничего хорошего из этого не получится, что вообщем и показывают твои примеры.
S>Естественный ассоциативный доступ — это запросы к объектному представлению с использованием логики.
Не ищи естественности там где ее нет.
S> Запросы к "данным" да еще и без логики — не естественны.
Хм, я вообще не понимаю, когда ты начинаешь оперировать категориями "естественности", может из-за этого и все проблемы?
S>И навигационный доступ намного более естественный ем такие запросы.
То-то ты с ним такие проблемы имеешь.
S>Внутри обычной СУБД в планах выполнения запросов часто встречается UNIQUE INDEX UNIQUE SCAN, что есть суть доступ по ключу.
Часто, но не на столько часто, чтобы быть узким местом.
S> А для настольной СУБД — запросто можно вынести и наружу, таким образом получив фактически быстрый навигационный доступ.
Зачем, если и так все хорошо? Пойми-ты. Не нужен никому быстрый навигационный доступ. Точнее так — навигационный доступ, как правило, и так достаточно быстр, он отнюдь не самое узкое место, если его таковым искуственно не делать, чам, похоже ты в своей задаче и занимаешься.
S>А зачем мне десять разных представлений модели прикладной области? Да еще и разных по смыслу, как ты тут заявляешь.
Ты в серьез полагаешь, что модель данных можно сделать один-в-один с объектной? Более не "естественноую" конструкцию, пожалуй будет сложно придумать.
Там даже принципы организации моделей совершенно противоположные, объекты — лишь один из способов представления данных...
Хочешь простоты и единой модели — бери ООБД, сплошной навигационный доступ, но не говори потом, что я не предупреждал.
Здравствуйте, Merle, Вы писали:
M>Значит варианта два. Либо твоя задача — большое исключение и не для реляционных БД, либо ты ее неправильно описываешь, поскольку 99% задач сводятся к master/detail...
Я так не считаю. Выражаясь терминами UML, ты утверждаешь, что 99% ассоциаций — это аггрегации, и, соответственно оставшийся 1% — просто ассоциации. Чушь! Возми для примера AST для C# и посчитай.
S>>В конечном итоге любая программа — это машинные коды. И значит надо просто правильно написать их ! S>>Только почему же никто так не делает, а? M>Почему не делают? Делают.
В подывляющем большинстве случаев предпочитается все-таки некая абстракция, называемая языком программирования, которая автоматизирует большую часть работы.
M>Вот это как раз естественно, потому что с данными надо работать одним способом, а с объектами — другим. Потому что данные — это просто голая информация, а объект — в первую очередь поведение...
Данные — это просто технический слой, необходимый для сохранения/восстановления состояния программы. И все! И чем прозрачней этот слой — тем лучше. Разделение, о котором ты говоришь, обуславливается лишь текущим состоянием технологий, и никак не является филосовской самоцелью.
M>...и если мешать все это в кучу, то ничего хорошего из этого не получится, что вообщем и показывают твои примеры.
А мои примеры ничего плохого-то не показывают...
M>Не ищи естественности там где ее нет.
Искать естественность описания и работы с предметной областью — есть одна из целей разработчика любой технологии.
M>Хм, я вообще не понимаю, когда ты начинаешь оперировать категориями "естественности", может из-за этого и все проблемы?
Странно, что не понимаешь. Ведь это же твои слова, что ассоциативный доступ более естественный, чем навигационыый .
S>>И навигационный доступ намного более естественный ем такие запросы. M>То-то ты с ним такие проблемы имеешь.
Нет у меня проблем. Любая технология, пытающаяся автоматизировать что-либо вполне может быть сложной. Возми GC, для примера.
Реализация сложная — использование простое. Стандартная ситуация.
S>> А для настольной СУБД — запросто можно вынести и наружу, таким образом получив фактически быстрый навигационный доступ. M>Зачем, если и так все хорошо? Пойми-ты. Не нужен никому быстрый навигационный доступ. Точнее так — навигационный доступ, как правило, и так достаточно быстр, он отнюдь не самое узкое место, если его таковым искуственно не делать, чам, похоже ты в своей задаче и занимаешься.
Это потому, что ты искусственно пытаешься не использовать навигацию, там где бы это было в тему. А вот если ты перестанешь себя ограничивать, то навигационный доступ сразу станет узким местом.
S>>А зачем мне десять разных представлений модели прикладной области? Да еще и разных по смыслу, как ты тут заявляешь. M>Ты в серьез полагаешь, что модель данных можно сделать один-в-один с объектной? Более не "естественноую" конструкцию, пожалуй будет сложно придумать. M>Там даже принципы организации моделей совершенно противоположные, объекты — лишь один из способов представления данных...
Да делай ее какой хочешь. Главное — она есть просто способ сохранить/восставовить состояние объектной модели. И поэтому она не должна мозолить мне глаза на уровне работы с объектной моделью, т.е. на уровне логики.
M>Хочешь простоты и единой модели — бери ООБД, сплошной навигационный доступ, но не говори потом, что я не предупреждал.
Как я уже говорил, я за смешанный тип. Должен присутствовать и навигационный доступ и все прелести реляционной БД.
Здравствуйте, Serginio1, Вы писали:
S> ну получить тип по &byte[0] не проблема, просто ссылка на структуру. Но про указатели мы не забываем. То бишь ничего не стоит. Практика это доказывает. В нативе вообще проще т.к. просто копирование в типизированный буффер (структуру).
Нет. Не только это. Ты должен хранить типизированные значения в одном месте, а кэш страниц в другом. В наиболее криминальном случае нагрузка на память можно умножать на 2.
Здравствуйте, stalcer, Вы писали:
S>Я так не считаю.
Твое право.
S> Выражаясь терминами UML, ты утверждаешь, что 99% ассоциаций — это аггрегации, и, соответственно оставшийся 1% — просто ассоциации.
Во-первых я говорил совсем другое, а во-вторых, причем тут UML?
S>Чушь!
Ну ты понял..
S>В подывляющем большинстве случаев предпочитается все-таки некая абстракция, называемая языком программирования, которая автоматизирует большую часть работы.
А, ты об этом... Так тут вопрос в выборе правильной абстракции и не зря SQL совершенно отдельный язык, исключительно для работы с данными.
S>Данные — это просто технический слой, необходимый для сохранения/восстановления состояния программы. И все!
Не, мужик, все совсем не так. Я бы даже сказал строго наоборот. Твоя программа может измениться 10 раз, полностью поменяется объектная модель и ее предназначение, а данные останутся тми же самыми... Так что данные первичны, а твоя программа всего лишь фантик, который можно раскрасить как тебе нравится, потом выкинуть и навернуть другой, поверх той же самой конфетки с данными.
S> И чем прозрачней этот слой — тем лучше.
В этом-то и есть твое основное заблуждение.
S>Разделение, о котором ты говоришь, обуславливается лишь текущим состоянием технологий, и никак не является филосовской самоцелью.
С этим никто не спорит, но с текущим состоянием технологий приходится мириться.
S>А мои примеры ничего плохого-то не показывают...
Здрасьте, а кто тут плакался по поводу потрясающий производительности навигационного доступа?
S>Искать естественность описания и работы с предметной областью — есть одна из целей разработчика любой технологии.
Ну да, готовй продукт получить — это вторично...
S>Странно, что не понимаешь. Ведь это же твои слова, что ассоциативный доступ более естественный, чем навигационыый .
Нет, про "естественность" это все твое, я просто пытаюсь пользоваться твоей терминологией, чтоы понятнее было.
S>Нет у меня проблем.
Тогда о чем разговор? Значит проблем с навигационным доступом таки нет.
S>Это потому, что ты искусственно пытаешься не использовать навигацию, там где бы это было в тему.
Как раз наоборот. Я использую последовательный доступ, там где он "в тему", пользуясь теми возможностями, что мне предоставляет реляционка и не используя навигационный там, где это не надо.
S> А вот если ты перестанешь себя ограничивать, то навигационный доступ сразу станет узким местом.
Я себя не ограничиваю, это ты себя ограничиваешь исключительно навигационным доступом, естественно после этого все в него упирается.
S>Главное — она есть просто способ сохранить/восставовить состояние объектной модели. И поэтому она не должна мозолить мне глаза на уровне работы с объектной моделью, т.е. на уровне логики.
Да вторична твоя логика, вместе с объектной моделью. Это, кстати, вечная проблема кривых ORM-ов, которые пытаются забыть про данные и делать все по объектному, чтобы было "прозрачно", а надо ровно наоборот. Посмотри на DLinq, вот там они как раз пляшут в первую очередь от данных и подгоняют объекты под данные, получая, так вожделенную тобой прозрачность, но уже с правильной стороны.
S>Как я уже говорил, я за смешанный тип. Должен присутствовать и навигационный доступ и все прелести реляционной БД.
Ну так и используй эти прелести реляционной БД и забудешь про свою навигацию, как про страшный сон...
S>Может по таблице A и последовательно, а по B — с поиском по ключу (UNIQUE INDEX UNIQUE SCAN), а потом еще и доступ к записи в таблице B по найденному в индексе rowid (тоже не последовательно по отношению к физическому хранению). S>Что, не так скажешь?
Нет, конечно же не так. Да, иногда задача сводится к подъему связанных записей из справочников. Но как только потребуется наложить нетривиальное условие на B, навигационный доступ тут же уйдет курить. А ассоциативный сможет применить другой набор индексов; причем порядок применения предикатов будет определяться не только самой формулировкой задачи, но также и статистикой — если B, удовлетворяющих предикату, значительно меньше, чем A, то никаких последовательных вытаскиваний B по ключу из A не будет.
Именно поэтому умные дяди двадцать пять лет назад отказались от сетевых СУБД — реляционка не хуже них выполняет unique index unique scan. Мы можем оформить запрос select * from B where B.pk = @key в как-бы-навигационном виде. Но это декорация, и совершенно не факт, что ее стоит делать удобной в применении. Потому как это будет провоцировать разработчиков на использование навигационного доступа, что вставляет палки в колеса оптимизатора. Косяк в том, что с системой, написанной в навигационном стиле, практически ничего полезного сделать нельзя. Только переписать. А система, построенная в виде декларативного описания трансформаций хранимых данных в выдаваемые данные, можно еще очень много всего сделать. Мне не очень нравится сам по себе SQL из-за слабых возможностей декомпозиции.
В современной реляционной системе можно пойти намного дальше. В частности, реализация ленивой семантики в реляционных выражениях может существенно сэкономить усилия по повторному использованию. Опять же, можно снять проблемы с динамическим построением запросов в зависимости от наличия/отсутствия ограничений. Современные реализации SQL идут в этом плане очень недалеко: можно определять view, но это жутко статические сущности. Можно применять временные таблицы, но у них "шустрая" семантика, и оптимизатору негде развернуться.
В нормальной системе я могу объявить переменную типа "реляция", могу динамически построить из нее выражение, могу передать это выражение дальше, а могу просто исполнить. Можно будет решить, откуда выбирать данные в одном месте, выбрать фильтр для применения к ним в другом, а порядок сортировки определить в третьем.
Но навигация вредит всему этому. Она слишком императивна, и требует от разработчика слишком точного представления о том, как именно устроены данные, с которыми он работает.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Merle, Вы писали:
S>> Выражаясь терминами UML, ты утверждаешь, что 99% ассоциаций — это аггрегации, и, соответственно оставшийся 1% — просто ассоциации. M>Во-первых я говорил совсем другое, а во-вторых, причем тут UML?
UML для того, чтобы обозначить термины. А что другое ты говорил. Чем оно отличается от этого?
Здравствуйте, Sinclair, Вы писали:
S>В нормальной системе я могу объявить переменную типа "реляция", могу динамически построить из нее выражение, могу передать это выражение дальше, а могу просто исполнить. Можно будет решить, откуда выбирать данные в одном месте, выбрать фильтр для применения к ним в другом, а порядок сортировки определить в третьем.
Это вот очень правильная тема. Я тоже над этим давно думаю .
S>Но навигация вредит всему этому. Она слишком императивна, и требует от разработчика слишком точного представления о том, как именно устроены данные, с которыми он работает.
Я считаю так: запросы (и переменные типа "реляция") — это более высокий уровень. Императивная программа (и навигационный доступ) — более низкий (обработка результатов запросов).
Полностью от навигационного доступа избавляться нельзя — страдает модульность, особенно в условиях OO пардигмы с наличием полиморфизма.
Здравствуйте, stalcer, Вы писали:
S> А что другое ты говорил. Чем оно отличается от этого?
Я говорил, что 99% сводится к master/detail, а так как в SQL-е нет наследования и прочих прелестей ОО, то и получается master/detail по факту — это к вопросу о разных моделях в ОО и реляционке.
Здравствуйте, Merle, Вы писали:
M>Я говорил, что 99% сводится к master/detail, а так как в SQL-е нет наследования и прочих прелестей ОО, то и получается master/detail по факту — это к вопросу о разных моделях в ОО и реляционке.
Оно, конечно, так. В реляционке другая модель. Там и аггрегация и не аггрегация — все одно внешний ключ. Но, по сути то они остаются разными — аггрегации и просто ассоциации. И даже будучи реализованными одинаково (через внешний ключ), среднестатистические сценарии работы с ними — разные. Тот случай, который описываешь ты — больше подходит для связей, которые по сути своей — аггрегации. А для просто ассоциаций, не являющихся аггрегациями — мой сценарий.
Здравствуйте, stalcer, Вы писали: S>Я считаю так: запросы (и переменные типа "реляция") — это более высокий уровень. Императивная программа (и навигационный доступ) — более низкий (обработка результатов запросов).
Вот мне совершенно непонятно, что именно ты имеешь в виду под обработкой результатов запроса. Если мы говорим о реляционном запросе, то вся обработка сводится к последовательному перебору кортежей.
Если мы говорим о некоторой иерархии, которая является результатом запроса, то ее логично представлять в виде XML — т.к. для него есть как произвольный доступ, так и однонаправленный последовательный перебор, а также механизмы декларативных запросов и трансформаций. S>Полностью от навигационного доступа избавляться нельзя — страдает модульность, особенно в условиях OO пардигмы с наличием полиморфизма.
А можно раскрыть этот тезис поподробнее? В каком месте навигационный доступ поможет модульности?
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Ну, в принципе да. У тебя есть альтернативное определение термина "доступ"?
Просто для него существует так же update, delete и insert.
S>Гм. В этом месте не понял. SQL предназначен для того, чтобы выполнять операции с данными. Никаких объектов там нет. Есть кортежи. При этом сложную логику, зависящую от состояния кортежа, в SQL вполне можно использовать. Хотя, конечно же, применение индексов существенно затрудняется сложными выражениями (читай — делается невозможным). Низкая производительность самих по себе выражений лежит исключительно на совести реализаторов — никто не мешает в движке SQL скомпилировать выражение 2*a*a + SQRT(b) / с прямо в нативный код, а не париться с интерпретацией.
Такие простые выражения — да. Но если посложней, то уже идет переход на курсоры. А курсоры — это навигационный доступ. Я сомневаюсь что можно построить язык запросов который мог бы удовлетворить все вычислимые задачи.
S>Вина SQL в том, что это диалоговый язык. Убил бы того, кто это придумал. Результатом стейтмента Select должна быть не отправка резулт сета в трубу, а выражение реляционного типа. S>Что-то вроде табличной переменной в MS SQL, только без выполнения запроса. Чтобы можно было делать так: S>
S>declare @a (id int, code int)
S>set @a = select id, type from sysobjects
S>if not @type is null
S> set @a = select * from @a where type = @type
S>return @a
S>
Хорошая весчь. Прям XQuery(который в действительности умеет работать с реляционными данными). Я как-то продумывал математику на такую шнягу на основе Фегараса. Ну для чистого sql эта вещь не слишком. Лучше делать язык который учитывает сразу взаимосвязи.
S>Все как в функциональных языках — берем ленивые выражения, строим из них другие и т.п. И только когда нам наконец понадобились сами данные, отдаем запрос на выполнение.
+1
S>А это ты к чему? Сложности редактирования сами по себе слабо связаны с SQL. Их суть в том, что сам запрос надо рассматривать как объект. Что, впрочем, вполне противоречит принятому в SQL идиотизму с желанием как можно быстрее перейти "от слов к делу", точнее от текста запроса к табличке с данными.
Это к вопросу о навигации. Фактически для любой функциональности надо иметь некоторое дерево(или связанный граф). Фактически, легко ассоциативно найти корень дерева(или набор корней) и после пройтись от объекта к объекту. В случае SQL такие проходы(а их бывают очень много) выливаются в генерацию SQL.
GZ>>В шестых, весьма удобно отойти от отношения как такового, а перейти к навигации в определенных случаях. Например у тебя форма. Обычно данные в такой форме есть дерево по которому в случае навигационного доступа было бы удобно бегать. S>Это я тоже не очень понимаю. Навигация суть частный случай поиска по первичному ключу.
Ну не всегда. Навигация по foreign key еще может быть. Но в случае применения навигационного доступа, я вполне могу гулять как захочу без sql.
Навигация в локальных системах ничего не стоит. Однако при реализации некоторый задач, чертовски удобная штука. Ессно, это не отрицает нужности ассоциативного поиска.
Здравствуйте, Sinclair, Вы писали:
S>Но навигация вредит всему этому. Она слишком императивна, и требует от разработчика слишком точного представления о том, как именно устроены данные, с которыми он работает.
Вопрос 1 — чем может помешать оптимизатору навигационный доступ в локальной системе? Я согласен на иное, что оптимизатор мешается и слишком избыточен для навигационного доступа.
Вопрос 2. Такое впечатление что ты когда говоришь о навигационном доступе, говоришь о проходах на физическом уровне. Это действительно, очень нехорошо. Но если говорить о проходах на логическом уровне (который потом уже будет трансформирован в физический) то проблем не вижу.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Serginio1, Вы писали:
S>> ну получить тип по &byte[0] не проблема, просто ссылка на структуру. Но про указатели мы не забываем. То бишь ничего не стоит. Практика это доказывает. В нативе вообще проще т.к. просто копирование в типизированный буффер (структуру). GZ>Нет. Не только это. Ты должен хранить типизированные значения в одном месте, а кэш страниц в другом. В наиболее криминальном случае нагрузка на память можно умножать на 2.
Это касается только ссылочных типов. Доступ осуществляется через свойства, и выделение из поля объекта по требованию, если объект нужен кратковременно, то в зависимости от версии GC мы теряем время только на десериализацию которая ничтожна. Зачем хранить все прочитанные объекты???
У нас настольная БД раз, ничего кэшировать не надо (а со страницами Файловая сиситема хорошо сама справляется).
Для примера 1С работает по такому принципу и большинство удовлетворяет, а основные потери связаны отнють не с десериализацией.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, GlebZ, Вы писали: S>>Ну, в принципе да. У тебя есть альтернативное определение термина "доступ"? GZ>Просто для него существует так же update, delete и insert.
А-а. Ну, тут понятия "ассоциативности" несколько размываются. Сама по себе реляционная алгебра ничего о модификациях не говорит.
С точки зрения практики, все же есть некоторые "настоящие" отношения, которые собственно хранятся, а есть результаты вычисления выражений.
Вся ассоциативность операций сводится к:
— для удаления: отбор кортежей на основе декларативно заданного предиката, вместо прямого указания "удали вот это"
— для вставки: формирование множества кортежей, которые манием руки объявляются "отныне существующими", опять же вместо вставки чего-то куда-то.
— для обновления вообще все сложно. Нужно указать сразу как множество жертв операции, так и собственно действие, которое над ними нужно совершить.
GZ>Такие простые выражения — да. Но если посложней, то уже идет переход на курсоры.
Ну например? GZ>А курсоры — это навигационный доступ. Я сомневаюсь что можно построить язык запросов который мог бы удовлетворить все вычислимые задачи.
А в чем собственно затык? Язык SQL уже собственно turing-complete. GZ>Хорошая весчь. Прям XQuery(который в действительности умеет работать с реляционными данными).
Я XQuery собственно не знаю. Но с точки зрения функциональщины (где собственно выражения являются first-class citizens) SQL не слишком далеко убежал от Клиппера. Разве что результат операции по умолчанию не скидывается в новое персистентное отношение, а уезжает клиенту. Тьфу! GZ>Я как-то продумывал математику на такую шнягу на основе Фегараса.
Очень хорошо. GZ>Ну для чистого sql эта вещь не слишком.
Гм? Не уверен, но имхо это было бы весьма и весьма удобно. GZ>Лучше делать язык который учитывает сразу взаимосвязи.
Ты имеешь в виду автоматизацию джойнов? Вроде select * from orders where order.Customer.Name like "Иванов%"? S>>Все как в функциональных языках — берем ленивые выражения, строим из них другие и т.п. И только когда нам наконец понадобились сами данные, отдаем запрос на выполнение. GZ>+1 GZ>Это к вопросу о навигации. Фактически для любой функциональности надо иметь некоторое дерево(или связанный граф).
Э-э? Я вот совершенно не уверен в справедливости данного утверждения. Это всего лишь один из способов достижения "любой функциональности". Вон, в Декларативном Программировании народ поопытнее меня, и вроде бы там упоминалось построение даже и интерактивных приложений на чисто функциональных языках, где навигации как таковой нету. Ну, может быть я и заблуждаюсь. GZ>Фактически, легко ассоциативно найти корень дерева(или набор корней) и после пройтись от объекта к объекту. В случае SQL такие проходы(а их бывают очень много) выливаются в генерацию SQL.
Ну мы же говорим не о самом по себе SQL, а о том, что вместо указателей у нас могут быть связи, и собственно "проход" от объекта к объекту оформляется в виде подходящего запроса, сворачивающего граф в IEnumerable. S>>Это я тоже не очень понимаю. Навигация суть частный случай поиска по первичному ключу. GZ>Ну не всегда. Навигация по foreign key еще может быть.
А какие у нас еще есть случаи? Навигация — это либо разыменование ссылки, либо итерирование коллекции. Вариантов нет.
Собственно аналогом ссылки является PK, а коллекция суть результат некоторого запроса. GZ>Но в случае применения навигационного доступа, я вполне могу гулять как захочу без sql.
Нет, просто в навигационном доступе намертво вшиты некоторые запросы. В частности прямая навигация по FK и обратная навигация (типа Order.Items).
GZ>Навигация в локальных системах ничего не стоит. Однако при реализации некоторый задач, чертовски удобная штука. Ессно, это не отрицает нужности ассоциативного поиска.
Ышшо рас: навигация суть частный случай ассоциативного поиска. С очень убогими ассоциациями
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>>Полностью от навигационного доступа избавляться нельзя — страдает модульность, особенно в условиях OO пардигмы с наличием полиморфизма. S>А можно раскрыть этот тезис поподробнее? В каком месте навигационный доступ поможет модульности?
public class A { public int x; }
public class B { public int y; }
public class CBase
{
public abstract bool M();
}
public C1: CBase
{
public A a;
public override bool M() { return (a.x != 0); } // Здесь.
}
public C2: CBase
{
public B b;
public override bool M() { return (b.y != 0); } // Здесь.
}
void Main()
{
foreach (CBase obj in (select xt.* from C_Tab xt)) // Можно так.if (obj.M())
...;
foreach (CBase obj in (select xt.* from C_Tab xt where xt.M())) // Можно и так. Все равно.
...;
}
Здравствуйте, Sinclair, Вы писали:
S>Как это чем? Навигация — это физический план запроса. Это императивная конструкция, которая оперирует понятием ссылок. Навигация подменяет смысл операции ее выполнением. В результате эксплуатации навигация превращается в ритуал, которому тупо следует приложение, вместо того, чтобы отбросить все ненужное S>В тех случаях, когда навигационный доступ соответствует оптимальному плану запроса это так. Но как только оптимальность перестает быть действительной, только оптимизатор имеет шанс выбрать альтернативный план.
Навигация не нужна для операции фильтрации 10 тысяч кортежей из пары миллионов при пяти джоинах. Это всего лишь простое и легкое получение связанных объектов. Можешь называть его синтаксическим сахаром для небольших данных.
GZ>>Вопрос 2. Такое впечатление что ты когда говоришь о навигационном доступе, говоришь о проходах на физическом уровне. S>Конечно. GZ>>Это действительно, очень нехорошо. Но если говорить о проходах на логическом уровне (который потом уже будет трансформирован в физический) то проблем не вижу. S>Я не против того, чтобы предикат был записан в форме distinct Item.Order.Customer where Item.Good = elephant. Но это — не навигация. Это просто другое представление ассоциативного запроса.
Немного не так. Давай возьмем ту шнягу с ленивыми вычислениями что представил ты, и выделим логический и физический уровень. Допустим физический уровень — это чистый набор таблиц. И допустим логический уровень — это некоторый entity к которому в метаданных прописан запрос получения(можно взять за образец BLToolkit).
Итого:
val entity=from table1 inner join tablejoin on (bla-bla) select id, b, c
нам нужно получить entity2 который связан с аттрибутом с, как с.a, и идентификатор entity = 10
val entity=from table select id, b, c
val entity2=from table1 select id, e, f
var res=from entity2, entity where entity2.c=entity.id and entity.id=10 select entity
что выливается в запрос
select table1.* from table1 inner join tablejoin on (bla-bla) inner join table2 on (table1.c=table2.id) where table1=10
А так нравится?
И вся эта нехилая шняга в использовании будет проста
Здравствуйте, stalcer, Вы писали: S>>А можно раскрыть этот тезис поподробнее? В каком месте навигационный доступ поможет модульности? S>void Main() S>{ S> foreach (CBase obj in (select xt.* from C_Tab xt)) // Можно так. S> if (obj.M()) S> ...;
Абсолютное зло, потому как запрещает использование индексов, как бы ни были они придуманы S> foreach (CBase obj in (select xt.* from C_Tab xt where xt.M())) // Можно и так. Все равно. S> ...; S>} S>[/c#]
А здесь вообще нет никакой навигации. Впрочем, в первом примере никакой навигации тоже нет. Ты выполнил вполне ассоциативный запрос, а затем затеял некоторую дополнительную обработку. Ну и что? С тем же успехом ты мог заняться этим и для классического DataSet. Что характерно, ты сам же привел пример с полиморфизмом, в котором навигационный доступ не нужен.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, GlebZ, Вы писали: S>>В тех случаях, когда навигационный доступ соответствует оптимальному плану запроса это так. Но как только оптимальность перестает быть действительной, только оптимизатор имеет шанс выбрать альтернативный план. GZ>Навигация не нужна для операции фильтрации 10 тысяч кортежей из пары миллионов при пяти джоинах. Это всего лишь простое и легкое получение связанных объектов. Можешь называть его синтаксическим сахаром для небольших данных.
Ничего не понимаю. Я же сказал уже трижды — навигация суть убогий частный случай ассоциативного доступа. Я не против сахара.
GZ>Немного не так. Давай возьмем ту шнягу с ленивыми вычислениями что представил ты, и выделим логический и физический уровень. Допустим физический уровень — это чистый набор таблиц. И допустим логический уровень — это некоторый entity к которому в метаданных прописан запрос получения(можно взять за образец BLToolkit). GZ>Итого: GZ>
GZ>val entity=from table1 inner join tablejoin on (bla-bla) select id, b, c
GZ>
GZ>нам нужно получить entity2 который связан с аттрибутом с, как с.a, и идентификатор entity = 10 GZ>
GZ>val entity=from table select id, b, c
GZ>val entity2=from table1 select id, e, f
GZ>var res=from entity2, entity where entity2.c=entity.id and entity.id=10 select entity
GZ>
GZ>что выливается в запрос GZ>
GZ>select table1.* from table1 inner join tablejoin on (bla-bla) inner join table2 on (table1.c=table2.id) where table1=10
GZ>
GZ>А так нравится?
Ну и что? Вся нехилость этого запроса, получается, скрыта. Кстати, для конкретно этого примера вполне достаточно сделать
create view entity as select id, b, c from table
create view entity2 as select id, e, f from table1
И вся эта нехилая шняга в использовании будет проста:
select entity.* from entity inner join entity2 on entity.c=entity2.id where entity2.id=10
GZ>И вся эта нехилая шняга в использовании будет проста GZ>
GZ>entity2=entity1.c
GZ>
Вот это мне вообще непонятно. Ну написали мы кусок Where. Дальше-то что? Это какой-то синтаксис без семантики. Все равно придется писать
from entity where entity.c = 10 select
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>А здесь вообще нет никакой навигации. Впрочем, в первом примере никакой навигации тоже нет. Ты выполнил вполне ассоциативный запрос, а затем затеял некоторую дополнительную обработку. Ну и что? С тем же успехом ты мог заняться этим и для классического DataSet. Что характерно, ты сам же привел пример с полиморфизмом, в котором навигационный доступ не нужен.
Да навигация-то была в реализациях метода M(). Я же специально жирным выделил. Вот попробуй ее оттуда убрать не меняя смысла. Придеться переносить в запрос, что и приводит к нарушению инкапсуляции (модульности).
Здравствуйте, stalcer, Вы писали:
S>Да навигация-то была в реализациях метода M(). Я же специально жирным выделил. Вот попробуй ее оттуда убрать не меняя смысла. Придеться переносить в запрос, что и приводит к нарушению инкапсуляции (модульности).
А! Извини, не сразу заметил. Ну да, есть такая проблема. Точнее, полноценный OODBMS движок должен сам раскручивать такие вещи:
select xt.* from C_Tab xt where xt.M()
-->
select c1 from Extent<C1> c1 where c1.C1::M()
UNION
select c2 from Extent<C2> c2 where c2.C2::M()
-->
select c1 from Extent<C1> c1 where c1.a.x != 0
UNION
select c2 from Extent<C2> c2 where c2.b.y != 0
-->
дальше уже идет построение физического плана для обычного мономорфного запроса. Ну там типа
UNION(
HASH_JOIN(
CLUSTERED_INDEX_SEEK(A_X_ID, != 0), // сканируем индекс по A(x, id)
CLUSTERED_INDEX_SCAN(C1_A) // сканируем FK- индекс по C1(a)
),
LOOP_JOIN(
INDEX_SCAN(C2_PK_B), // сканируем индекс по C2(b)
TABLE_SCAN(B, B.id=C2_B && y!=0)
)
)
Но смысл остается в том, что поиск по-прежнему ведется ассоциативно.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Кроме, конечно, сложности реализации такого движка, есть здесь, как мне кажеться, и более фудаментальная проблема. Дело в том, что оптимизации такие будут возможны только для простых случаев, а дальше кирдык. И кирдык этот оттого, что логика пишется а императивном языке.
Здравствуйте, Sinclair, Вы писали:
S>А-а. Ну, тут понятия "ассоциативности" несколько размываются. Сама по себе реляционная алгебра ничего о модификациях не говорит. S>С точки зрения практики, все же есть некоторые "настоящие" отношения, которые собственно хранятся, а есть результаты вычисления выражений. S>Вся ассоциативность операций сводится к: S>- для удаления: отбор кортежей на основе декларативно заданного предиката, вместо прямого указания "удали вот это" S>- для вставки: формирование множества кортежей, которые манием руки объявляются "отныне существующими", опять же вместо вставки чего-то куда-то. S>- для обновления вообще все сложно. Нужно указать сразу как множество жертв операции, так и собственно действие, которое над ними нужно совершить.
Ага. А если посмотреть сценарии использования, то в 90 процентов случаев(а может и больше) нам просто нужно сохранить объект с некоторым PK.
S>А в чем собственно затык? Язык SQL уже собственно turing-complete.
В честь чего? Может ты имел ввиду T-SQL?
GZ>>Хорошая весчь. Прям XQuery(который в действительности умеет работать с реляционными данными). S>Я XQuery собственно не знаю. Но с точки зрения функциональщины (где собственно выражения являются first-class citizens) SQL не слишком далеко убежал от Клиппера. Разве что результат операции по умолчанию не скидывается в новое персистентное отношение, а уезжает клиенту. Тьфу!
+1
GZ>>Я как-то продумывал математику на такую шнягу на основе Фегараса. S>Очень хорошо.
Здесь больше подойдут кимовская оптимизация + beta редукция. Фегарасовская математика подразумевает другой набор реляционных операций.
GZ>>Лучше делать язык который учитывает сразу взаимосвязи. S>Ты имеешь в виду автоматизацию джойнов? Вроде select * from orders where order.Customer.Name like "Иванов%"?
Да.
S>А какие у нас еще есть случаи? Навигация — это либо разыменование ссылки, либо итерирование коллекции. Вариантов нет.
+1. S>Собственно аналогом ссылки является PK, а коллекция суть результат некоторого запроса.
+1 GZ>>Но в случае применения навигационного доступа, я вполне могу гулять как захочу без sql. S>Нет, просто в навигационном доступе намертво вшиты некоторые запросы. В частности прямая навигация по FK и обратная навигация (типа Order.Items).
Если мы не будем отрывать физического хранения от логического, то да. Если будем отрывать, то все может быть несколько сложней и интересней.
GZ>>Навигация в локальных системах ничего не стоит. Однако при реализации некоторый задач, чертовски удобная штука. Ессно, это не отрицает нужности ассоциативного поиска. S>Ышшо рас: навигация суть частный случай ассоциативного поиска. С очень убогими ассоциациями
А ненужно больше. Еще раз повторю уже слева направо:
Несложное приложение можно разделить на два локальных сценария:
1. Мы показываем некоторый грид (и тут без ассоциативного поиска никуда не денешся).
2. Мы редактируем некоторый объект в форме. В данном случае у нас есть некоторая куча взаимосвязанных объектов, у которых можно выделить один объект как корень. Плюс к этому, при редактировании мы должны поднимать справочники значений. И вот здесь, навигационный способ значительно продуктивнее для программиста, чем долгое вбивание запросов.
Здравствуйте, stalcer, Вы писали:
S> А для просто ассоциаций, не являющихся аггрегациями — мой сценарий.
Но твой сценарий, когда просто ассоциации — это еденичные выборки и они не оказывают заметного влияния на производительность всей системы, с чего собственно и начался разговор.
Здравствуйте, Sinclair, Вы писали:
S>Ничего не понимаю. Я же сказал уже трижды — навигация суть убогий частный случай ассоциативного доступа. Я не против сахара.
Дык я и не возражалЪ.
S>Ну и что? Вся нехилость этого запроса, получается, скрыта. Кстати, для конкретно этого примера вполне достаточно сделать
Нее. Вьюхи вряд ли нужны. Их нужно поддерживать на уровне механизма БД, что добавляет сложности. Мне больше нравится, чтобы каждый объект, сам по себе был набором запросов. Ну типа как это могло выглядить в BLToolkit.
public PersonDataSource:DataSource
{
Query<T> Select(){return from table1 t, table2 t2 select t1;}
........
}
S>Вот это мне вообще непонятно. Ну написали мы кусок Where. Дальше-то что? Это какой-то синтаксис без семантики. Все равно придется писать S>
S>from entity where entity.c = 10 select
S>
Безусловно. Корень в навигации практически всегда нужен.
Здравствуйте, Merle, Вы писали:
M>Но твой сценарий, когда просто ассоциации — это еденичные выборки и они не оказывают заметного влияния на производительность всей системы, с чего собственно и начался разговор.
Моя твоя непониает,
Рассудок мой изнемогает.
И т.п.
Здравствуйте, stalcer, Вы писали: S>Кроме, конечно, сложности реализации такого движка, есть здесь, как мне кажеться, и более фудаментальная проблема. Дело в том, что оптимизации такие будут возможны только для простых случаев, а дальше кирдык. И кирдык этот оттого, что логика пишется а императивном языке.
С т.з. тезиса Черча императивные и декларативные языки суть одно
А с точки зрения здравого смысла мы вполне можем попытаться привести метод M() к функциональному виду. И это, очевидно, удастся в простых случаях (типа тех же лямбда-выражений). В случае неудачи мы можем откатиться к методу полного перебора. Как минимум это не хуже, чем классический навигационный способ.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, GlebZ, Вы писали: S>>А в чем собственно затык? Язык SQL уже собственно turing-complete. GZ>В честь чего? Может ты имел ввиду T-SQL?
Нет, зачем? Для справки: исчисление функций, где есть функция 0, инкремент, и выбор n-ого аргумента, является turing-complete.
S>>Нет, просто в навигационном доступе намертво вшиты некоторые запросы. В частности прямая навигация по FK и обратная навигация (типа Order.Items). GZ>Если мы не будем отрывать физического хранения от логического, то да. Если будем отрывать, то все может быть несколько сложней и интересней.
Я не очень понимаю, что такое физическое и логическое хранение. Хранение бывает только одним — физическим. Есть логический уровень, который представляет хранимые данные в виде какой-то модели. Не могу придумать такой модели, в которой навигация была бы связана с чем-то, кроме банальных FK/PK. S>>Ышшо рас: навигация суть частный случай ассоциативного поиска. С очень убогими ассоциациями GZ>А ненужно больше. Еще раз повторю уже слева направо: GZ>Несложное приложение можно разделить на два локальных сценария: GZ>1. Мы показываем некоторый грид (и тут без ассоциативного поиска никуда не денешся). GZ>2. Мы редактируем некоторый объект в форме. В данном случае у нас есть некоторая куча взаимосвязанных объектов, у которых можно выделить один объект как корень. Плюс к этому, при редактировании мы должны поднимать справочники значений. И вот здесь, навигационный способ значительно продуктивнее для программиста, чем долгое вбивание запросов.
Совершенно непонятно, почему ты связываешь ассоциативность непременно с долгим вбиванием запросов . Длина запросов зависит от синтаксиса языка. Если мы сделаем удобный синтаксис для прямой и обратной навигации, то все придет само.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Sinclair wrote: > Не могу придумать такой модели, в которой навигация была бы > связана с чем-то, кроме банальных FK/PK.
Банально: OID является указателем на физическое расположение объекта
(позицию в файле). Тогда при навигационный доступ будет O(1), вместо
O(log N).
А если использовать при этом схемы с mmap'ом то вообще быстро получается.
Здравствуйте, Cyberax, Вы писали: C>Банально: OID является указателем на физическое расположение объекта C>(позицию в файле). Тогда при навигационный доступ будет O(1), вместо C>O(log N).
Зато апдейт будет O(N). Такая модель неприемлема для нестатических БД.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
C>>Банально: OID является указателем на физическое расположение объекта C>>(позицию в файле). Тогда при навигационный доступ будет O(1), вместо C>>O(log N). S>Зато апдейт будет O(N). Такая модель неприемлема для нестатических БД.
Вообще-то поиск для aпдейт легко можно уменьшить (с помощью bitmap индекса). Другой вопрос что O(1) сделать трудновато. Хотя бы потому что нужно адресоваться по индексу, и адресация для страниц — подразумевает O(log N).
Здравствуйте, Sinclair, Вы писали:
S>Нет, зачем? Для справки: исчисление функций, где есть функция 0, инкремент, и выбор n-ого аргумента, является turing-complete.
Все — начинаю все писать в SQL.
Смешно. Зачем цепляться за термины. Вполне понятно что для многих вещей он не применим без T-SQL. Он легко справляется с четко поставленной задачей, но не более того.
S>>>Нет, просто в навигационном доступе намертво вшиты некоторые запросы. В частности прямая навигация по FK и обратная навигация (типа Order.Items). GZ>>Если мы не будем отрывать физического хранения от логического, то да. Если будем отрывать, то все может быть несколько сложней и интересней. S>Я не очень понимаю, что такое физическое и логическое хранение. Хранение бывает только одним — физическим. Есть логический уровень, который представляет хранимые данные в виде какой-то модели.
Ессно, имелось именно это ввиду. S>Не могу придумать такой модели, в которой навигация была бы связана с чем-то, кроме банальных FK/PK.
Во первых я говорил о самом строении объекта. Но в принципе можно поговорить и о банальных FK/PK. У меня примеров вагон и маленькая тележка. Ну например:
Есть юридические лица. Есть физические лица. У них есть общие аттрибуты, есть разные аттрибуты. А у документа — есть свойство подписант, в роли которого может выступать и юридическое лицо, и физическое.
S>Совершенно непонятно, почему ты связываешь ассоциативность непременно с долгим вбиванием запросов . Длина запросов зависит от синтаксиса языка. Если мы сделаем удобный синтаксис для прямой и обратной навигации, то все придет само.
Ну, с длиной запросов, если брать подобный SQL синтаксис(или функциональный типа LINQ) — хреноватенько по любому. Есть еще одно непотребное свойство. Код не должен повторяться. Из-за того что код будет достаточно часто повторяться, а программист с головой, он выделит его в функцию. Не легче ли сразу решить для него проблему?
Sinclair wrote: > C>Банально: OID является указателем на физическое расположение объекта > C>(позицию в файле). Тогда при навигационный доступ будет O(1), вместо > C>O(log N). > Зато апдейт будет O(N).
С чего бы?
Перезапись полей объекта — O(1), удаление объекта O(1) — просто помещаем
его в список свободных объектв. Вставка объектов — тоже O(1).
Единственное, при физическом перемещении объекта (в результате изменения
размера, например) придется обновлять ссылающиеся на него объекты. А
будет ли это частой операцией?
GlebZ wrote: > S>Зато апдейт будет O(N). Такая модель неприемлема для нестатических БД. > Вообще-то поиск для aпдейт легко можно уменьшить (с помощью bitmap > индекса). Другой вопрос что O(1) сделать трудновато. Хотя бы потому что > нужно адресоваться по индексу, и адресация для страниц — подразумевает > O(log N).
Почему, просто записываем в OID физическую позицию в файле.
Здравствуйте, Cyberax, Вы писали:
C>Единственное, при физическом перемещении объекта (в результате изменения C>размера, например) придется обновлять ссылающиеся на него объекты. А C>будет ли это частой операцией?
Конечно же будет. А ты как хотел? Иначе наш файл окажется крайне дырявым. СУБД без физического перемещения в природе не бывает. Причем, что характерно, перемещается как правило не один объект, а сразу пачка.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
GlebZ wrote:
> S>Нет, зачем? Для справки: исчисление функций, где есть функция 0, > инкремент, и выбор n-ого аргумента, является turing-complete. > Все — начинаю все писать в SQL. > Смешно. Зачем цепляться за термины. Вполне понятно что для многих вещей > он не применим без T-SQL. Он легко справляется с четко поставленной > задачей, но не более того.
Он наврал, SQL не является Turing-complete (чистый, конечно). А вот T-SQL-надстройка — да, там всякие циклы и прочее.
Вот поэтому я и не люблю его использовать и другим не рекомендую — нарушает концептуальную чистоту... Лишь ради одного
может быть оправдано — гонка за производительностью.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Sinclair wrote: > C>Единственное, при физическом перемещении объекта (в результате изменения > C>размера, например) придется обновлять ссылающиеся на него объекты. А > C>будет ли это частой операцией? > Конечно же будет. А ты как хотел? Иначе наш файл окажется крайне > дырявым.
Не обязательно. Дырявым он будет если объекты удаляются, но не
пересоздаются (в противном случае дырки можно переиспользовать для новых
объектов).
> СУБД без физического перемещения в природе не бывает. Причем, > что характерно, перемещается как правило не один объект, а сразу пачка.
Пачки как раз хорошо оптимизируются.
Иван прав, на типовых системах, как настольных, так и серверных, самую тяжелую нагрузку создают выборки по рабочим таблицам, которые состоят из сотен тысяч или миллионов записей, да еще с джойнами на десяток-другой справочников. По сравнению с этим выборки единичных записей по первичному ключу для современной техники сущие мелочи.
... << RSDN@Home 1.2.0 alpha rev. 646 on Windows XP 5.1.2600.131072>>
Здравствуйте, Cyberax, Вы писали: C>Не обязательно. Дырявым он будет если объекты удаляются, но не C>пересоздаются (в противном случае дырки можно переиспользовать для новых C>объектов).
Не получится. См. "фрагментация памяти".
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Блин! Я думал, все, закончилась ветка .
AVK>Иван прав, на типовых системах, как настольных, так и серверных, самую тяжелую нагрузку создают выборки по рабочим таблицам, которые состоят из сотен тысяч или миллионов записей, да еще с джойнами на десяток-другой справочников. По сравнению с этим выборки единичных записей по первичному ключу для современной техники сущие мелочи.
Во-первых, "джойны на десяток-другой справочников" — это и есть доступ по первичному ключу. Во-вторых, я же не говорил про выборки "единичных записей". В третьих, не все же данные плоские, бывают (реже, конечно) деревья и графы, которые тоже нужно хранить и по которым бегать потом.
Sinclair wrote: > C>Не обязательно. Дырявым он будет если объекты удаляются, но не > C>пересоздаются (в противном случае дырки можно переиспользовать для новых > C>объектов). > Не получится. См. "фрагментация памяти".
Почему не получится? Объекты обычно имеют один размер, так что все
вполне нормально.
Ну и периодический запуск пылесоса тоже вполне возможен.
Здравствуйте, Cyberax, Вы писали: C>Почему не получится? Объекты обычно имеют один размер, так что все C>вполне нормально. Это где ж такие объекты выдают? Стоит добавить одно строковое поле — и упс, приплыли. C>Ну и периодический запуск пылесоса тоже вполне возможен. стоимость пылесосения, имхо, может оказаться неприемлемой.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Sinclair wrote: > C>Почему не получится? Объекты обычно имеют один размер, так что все > C>вполне нормально. > Это где ж такие объекты выдают? Стоит добавить одно строковое поле — и > упс, приплыли.
Смотря какие строки — если ограниченые, то все нормально. Я же не
утверждаю, что оно для всех случаев идеально
> C>Ну и периодический запуск пылесоса тоже вполне возможен. > стоимость пылесосения, имхо, может оказаться неприемлемой.
Может. Все от задачи зависит.
Здравствуйте, stalcer, Вы писали:
S>Блин! Я думал, все, закончилась ветка .
Если она тебе так мешает — не читай.
S>Во-первых, "джойны на десяток-другой справочников" — это и есть доступ по первичному ключу.
Не совсем. Джойн выполняет движок БД, и выполняет ее сразу над набором, поэтому обычно эта операция несколько больше, нежели простая навигация. Например, как уже Антон говорил, здесь может учитываться статистика, возможности чего, при явном задании навигации, движок лишен.
S> Во-вторых, я же не говорил про выборки "единичных записей". В третьих, не все же данные плоские, бывают (реже, конечно) деревья и графы, которые тоже нужно хранить и по которым бегать потом.
Совсем реже и обычно они не создают самой большой нагрузки. Деревянные данные, скажем, обычно либо выбираются ветками целиком (простейшая групповая операция), либо подгружаются по требованию плоскими уровнями (тоже самое). В янусе, к примеру, используется комбинация того и другого подхода, и при отображении дерева сообщений, запросы исключительно реляционные и плоские.
... << RSDN@Home 1.2.0 alpha rev. 646 on Windows XP 5.1.2600.131072>>
Здравствуйте, Cyberax, Вы писали:
C>GlebZ wrote: >> S>Зато апдейт будет O(N). Такая модель неприемлема для нестатических БД. >> Вообще-то поиск для aпдейт легко можно уменьшить (с помощью bitmap >> индекса). Другой вопрос что O(1) сделать трудновато. Хотя бы потому что >> нужно адресоваться по индексу, и адресация для страниц — подразумевает >> O(log N). C>Почему, просто записываем в OID физическую позицию в файле.
Не получится, индекс(а в особенности hash) как и страницы имеют тенденцию менять свой размер. А следовательно — перемещаться. Так что адрес по любому должен быть втой, или иной мере косвенным.
Если говорить об oid, то в ООБД есть понятия логического и физического OID.
GlebZ wrote: > C>Почему, просто записываем в OID физическую позицию в файле. > Не получится, индекс(а в особенности hash) как и страницы имеют > тенденцию менять свой размер. А следовательно — перемещаться. Так что > адрес по любому должен быть втой, или иной мере косвенным.
Индексы и блобы, естественно, надо хранить отдельно.
Здравствуйте, Cyberax, Вы писали:
C>GlebZ wrote: >> C>Почему, просто записываем в OID физическую позицию в файле. >> Не получится, индекс(а в особенности hash) как и страницы имеют >> тенденцию менять свой размер. А следовательно — перемещаться. Так что >> адрес по любому должен быть втой, или иной мере косвенным. C>Индексы и блобы, естественно, надо хранить отдельно.
varchar тоже? Если строка перестает умещаться на странице, ее надо будет перемещать на ту, где уместится.
GlebZ wrote: >> > C>Почему, просто записываем в OID физическую позицию в файле. >> > Не получится, индекс(а в особенности hash) как и страницы имеют >> > тенденцию менять свой размер. А следовательно — перемещаться. Так что >> > адрес по любому должен быть втой, или иной мере косвенным. > C>Индексы и блобы, естественно, надо хранить отдельно. > varchar тоже? Если строка перестает умещаться на странице, ее надо будет > перемещать на ту, где уместится.
varchar тоже. Причем можно использовать small string optimization — если
строка меньше N символов, то хранить ее в объекте, в противном случае —
в страничном хранилище.
Здравствуйте, Cyberax, Вы писали:
>> C>Индексы и блобы, естественно, надо хранить отдельно. >> varchar тоже? Если строка перестает умещаться на странице, ее надо будет >> перемещать на ту, где уместится. C>varchar тоже. Причем можно использовать small string optimization — если C>строка меньше N символов, то хранить ее в объекте, в противном случае — C>в страничном хранилище.
Тады ты потеряешь больше производительности чем приобретешь. Обычно varchar-строк больше чем 50 процентов типов в траблице. Как результат тебе придется зачитывать от 2 до n страниц при чтении строки.
Здравствуйте, Cyberax, Вы писали: C>varchar тоже. Причем можно использовать small string optimization — если C>строка меньше N символов, то хранить ее в объекте, в противном случае — C>в страничном хранилище.
Совершенно непонятно, как быть со строками, которые сильно короче N. Считаем потерю в (N-avg(len))*count допустимой?
Совершенно непонятно, как выбирать N. С учетом того, что маленькие значения будут приводить к очевидному оверхеду из-за доп. обращений (а лишние страничные обращения очень дороги), а большие — к потере пространства (и опять же лишним чтениям)...
Спор, конечно, в значительной мере теоретический, но на практике, насколько мне известно, все промышленные СУБД поддерживают record relocation. Я, честно говоря, не знаю, как удается держать RID стабильным при переносе записей со страницы на страницу, но скоро узнаю как с этим обстоит по крайней мере в MS SQL.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали: S>Спор, конечно, в значительной мере теоретический, но на практике, насколько мне известно, все промышленные СУБД поддерживают record relocation. Я, честно говоря, не знаю, как удается держать RID стабильным при переносе записей со страницы на страницу, но скоро узнаю как с этим обстоит по крайней мере в MS SQL.
Возможно если представить строку как список, то головная часть состоящая из длины строки и начальноы части строки и ссылки на следующую часть строки. В зависимости от размера можно выделять различные блоки для хранения, максимальной котороя будет размер логической страницы принятой в БД. (головная часть может состоять из 30 символов).
Это так для примера.
и солнце б утром не вставало, когда бы не было меня
В общем, после философских размышлений вокруг да около, я уперся в то, что не знаю как правильно интегрировать навигацию в движок запросов.
С одной стороны, хочется, чтобы можно было четко провести границу между выполнением запроса и потреблением его результатов. К примеру, у нас есть некий предикат, мы можем мучить его как угодно, но только в момент приведения его к IEnumerable собственно выполняется запрос. И модификации хранимых данных, к примеру, на этот IEnumerable уже не влияют.
Это означает, что мы не можем отдать, к примеру, IEnumerable<OrderItem>, если OrderItem — это персистент ентити, и у нее есть свойство OrderItem.Order, кое указывает на персистент же ентити Order. Потому не можем, что это называется "навигация", и в общем случае потребует выполнения отдельного запроса, а это в свою очередь ведет к массе пренеприятнейших проблем и семантических неоднозначностей на пустом месте.
Вот ведь как хорошо в plain SQL! Там никакой навигации нету, и максимум, что может себе позволить иметь OrderItem — это свойство OrderId, размеченное соответствующим атрибутом. Все ясно, как день: хочешь Order по OrderItem — иди в базу лишний раз, получай Order по OrderId. Ну или сразу выбирай все, что нужно.
Но тогда синтаксис становится чрезмерно громоздким. К чему нам эти Id? Их значения как таковые вовсе не нужны; Id бывают потребны только для FK и навигации.
Хочется писать в запросах вместо
select orderItem.* from orderItem inner join order on orderItem.OrderId = orderId
where order.Amount>100
просто
select * from orderItem where orderItem.Order.Amount > 100;
Это все хорошо для самописанного языка запросов — можно, к примеру, ввести спец.синтаксис для разыменования FK:
select * from orderItem where orderItem->Order.Amount > 100;
, но тогда теряются преимущества Linq в виде статической проверки запросов. А в Linq все честно — все предикаты описываются в коде делегатов, а стало быть, по возможностям запросы и "нормальный код" эквивалентны. Так что как только мы позволим OrderItem заиметь свойство Order, как к этому свойству тут же можно будет обратиться за пределами запроса.
Есть идеи, как можно разрулить эту идеологическую пропасть?
— Бросать исключение при попытке сделать dereference на FK-свойство за пределами запроса? (при выполнении запроса все равно никакого вызова get для этого свойства происходить не будет; вместо этого "под капотом" станет выполняться соответствующий join)
— Ограничить возможные результаты запроса потоками записей, состоящих из простых типов (принудительно "планаризовать" объектные данные). Богатая, кстати, идея, в плане 100% гарантии отсутствия злонамеренных побочных эффектов. Но неудобна тем, что затрудняет повторное использование запросов.
— Позволить в запросе намекать на то, какие данные еще могут понадобиться, и фактически отдавать не просто IEnumerable<OrderItem>, а целый граф объектов, до которых можно добраться по ссылкам из этих OrderItem (тогда результат dereference FK будет гарантированно одинаков и в запросе, и в "клиентском коде").
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>В общем, после философских размышлений вокруг да около, я уперся в то, что не знаю как правильно интегрировать навигацию в движок запросов. S>С одной стороны, хочется, чтобы можно было четко провести границу между выполнением запроса и потреблением его результатов. К примеру, у нас есть некий предикат, мы можем мучить его как угодно, но только в момент приведения его к IEnumerable собственно выполняется запрос. И модификации хранимых данных, к примеру, на этот IEnumerable уже не влияют.
Ну, собственно, так LINQ и работает. В случае standard query operators реализация такого поведения тривиальна, в случае DLINQ все, конечно, сложнее.
S>, но тогда теряются преимущества Linq в виде статической проверки запросов. А в Linq все честно — все предикаты описываются в коде делегатов, а стало быть, по возможностям запросы и "нормальный код" эквивалентны.
Не совсем так. Не забывай о том, что лямбды могут быть представлены анонимными методами, а могут ввиде expression tree. Очевидно, что DLINQ пользуется вторым, и столь же очевидно что DLINQ проглотит не любую лямбду.
S>Есть идеи, как можно разрулить эту идеологическую пропасть?
Я бы просто не отходил от реляционной модели.
S>- Бросать исключение при попытке сделать dereference на FK-свойство за пределами запроса? (при выполнении запроса все равно никакого вызова get для этого свойства происходить не будет; вместо этого "под капотом" станет выполняться соответствующий join) S>- Ограничить возможные результаты запроса потоками записей, состоящих из простых типов (принудительно "планаризовать" объектные данные). Богатая, кстати, идея, в плане 100% гарантии отсутствия злонамеренных побочных эффектов. Но неудобна тем, что затрудняет повторное использование запросов. S>- Позволить в запросе намекать на то, какие данные еще могут понадобиться, и фактически отдавать не просто IEnumerable<OrderItem>, а целый граф объектов, до которых можно добраться по ссылкам из этих OrderItem (тогда результат dereference FK будет гарантированно одинаков и в запросе, и в "клиентском коде").
Здравствуйте, AndrewVK, Вы писали: AVK>Ну, собственно, так LINQ и работает. В случае standard query operators реализация такого поведения тривиальна, в случае DLINQ все, конечно, сложнее.
Ну, там я не совсем уверен — мне казалось что standarв query operators имеют ленивую семантику (а тогда модификация исходной коллекции в процессе енумерирования выкинет InvalidOperationException). Впрочем, в данном контексте это не столь уж важно. S>>, но тогда теряются преимущества Linq в виде статической проверки запросов. А в Linq все честно — все предикаты описываются в коде делегатов, а стало быть, по возможностям запросы и "нормальный код" эквивалентны.
AVK>Не совсем так. Не забывай о том, что лямбды могут быть представлены анонимными методами, а могут ввиде expression tree. Очевидно, что DLINQ пользуется вторым, и столь же очевидно что DLINQ проглотит не любую лямбду.
Ну, я про себя думаю, что мы будем жить не с DLinq, а с каким-то своим ?Linq. Кроме того, если я правильно понял, то все зависит ровно от контекста, в котором мы употребляем лямбда експрешшн. Т.о. если мы не будем рисковать здоровьем и предлагать метод с сигнатурой типа DbTable<T>.Where(Predicate<T> where), куда может приехать любой делегат, а ограничимся только expression tree, то никаких чудес не возникнет.
Ну, и опять же очевидно, что мы тоже не обязаны глотать любую лямбду. Вон Dlinq не собирается этого делать — и ничего, никто в обмороке не лежит пока. Хотя, конечно, ultimate goal — это ровно предоставить 100% поддержку всего, что доступно в standard query operators и при этом при близком к теоретическому минимуму количестве page scan AVK>Я бы просто не отходил от реляционной модели.
Т.е. все же полноразмерные join? Кстати, не можешь кинуть в двух словах синтаксис джойнов в Dlinq? AVK>ИМХО первый вариант лучше всего.
Да, я тоже к нему склоняюсь. И волки целы, и овцы сыты.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Есть идеи, как можно разрулить эту идеологическую пропасть? S>- Бросать исключение при попытке сделать dereference на FK-свойство за пределами запроса? (при выполнении запроса все равно никакого вызова get для этого свойства происходить не будет; вместо этого "под капотом" станет выполняться соответствующий join) S>- Ограничить возможные результаты запроса потоками записей, состоящих из простых типов (принудительно "планаризовать" объектные данные). Богатая, кстати, идея, в плане 100% гарантии отсутствия злонамеренных побочных эффектов. Но неудобна тем, что затрудняет повторное использование запросов. S>- Позволить в запросе намекать на то, какие данные еще могут понадобиться, и фактически отдавать не просто IEnumerable<OrderItem>, а целый граф объектов, до которых можно добраться по ссылкам из этих OrderItem (тогда результат dereference FK будет гарантированно одинаков и в запросе, и в "клиентском коде").
Если я правильно помню, в DLinq реализован третий вариант, c Including.
Думаю, небольшим хаком можно и первый вариант получить.
А в пределе мечтаний, конечно хотелось бы, что бы количество загружаемых в запросе данных расчитывалось в компайл-тайме анализом кода, который будет эти данные использовать. Но первый же виртуальный вызов потребует переноса этого процесса в рантайм, а там понятно, что хотелось бы учитывать и вероятность того, понадобятся дополнительные данные или нет, учитывать и стоимость догрузки недостающих данных, и оверхед загрузки неиспользуемых.
И тогда ручная загрузка данных станет таким же моветоном, как и ручное управление памятью, и на каком-нибудь форуме устанут повторять, что пытаться обогнать с помощью ручной загрузки оптимизатор в неспецифических случаях практического смысла не имеет
Здравствуйте, Sinclair, Вы писали:
S>Ну, я про себя думаю, что мы будем жить не с DLinq, а с каким-то своим ?Linq.
Естественно.
S> Кроме того, если я правильно понял, то все зависит ровно от контекста, в котором мы употребляем лямбда експрешшн. Т.о. если мы не будем рисковать здоровьем и предлагать метод с сигнатурой типа DbTable<T>.Where(Predicate<T> where), куда может приехать любой делегат, а ограничимся только expression tree, то никаких чудес не возникнет.
Ну как бы тебе сказать. Да, формирование expression tree диктуется контекстом, а точнее типом параметров методов. Но множество допустимых expression tree больше можества допустимых для движка БД лямбд.
AVK>>Я бы просто не отходил от реляционной модели. S>Т.е. все же полноразмерные join?
Да.
S> Кстати, не можешь кинуть в двух словах синтаксис джойнов в Dlinq?
Нет. Я его сам не видел. Просто знаю что он вобще есть и все. Ждем очередного CTP.
Здравствуйте, Belsen, Вы писали:
B>А в пределе мечтаний, конечно хотелось бы, что бы количество загружаемых в запросе данных расчитывалось в компайл-тайме анализом кода, который будет эти данные использовать.
В компайл тайме малореально во-первых из-за ограничений языка (Влад, молчать ), а во-вторых из-за того что ряд данных (навроде статистики), может быть в компайл-тайме просто недоступен.
Отдельная песня, если вдруг захочется писать запрос в терминах интерфейсов, а реализацию брать из сборок в БД уже в рантайме.
B> Но первый же виртуальный вызов потребует переноса этого процесса в рантайм,
Виртуальность нужна только при наличии наследования, следовательно вначале надо определится с ним.
Здравствуйте, Sinclair, Вы писали:
S>Это означает, что мы не можем отдать, к примеру, IEnumerable<OrderItem>, если OrderItem — это персистент ентити, и у нее есть свойство OrderItem.Order, кое указывает на персистент же ентити Order. S>Потому не можем, что это называется "навигация", и в общем случае потребует выполнения отдельного запроса, а это в свою очередь ведет к массе пренеприятнейших проблем и семантических неоднозначностей на пустом месте.
Если уж мы собираемся работать с "персистент ентитями", то и думать надо (семантику задавать) по объектному. Навигация — она только в этом случае смысл имеет. То есть как минимум должен быть идентити-мап, чтобы объекты не дублировались в памяти.
А семантика — она здесь простая:
Во-первых не надо выполнять запрос вида:
select x.* from OrderItems x
А надо выполнять запрос вида:
selectxfrom OrderItems x
Что должно означать то, что мы выбираем ссылки на обекты OrderItem. OrderItem ведь ссылочный тип. Ну и, собственно, получается, что результатом выполнения запроса будет набор ссылок, который действительно после выполнения уже не будет зависеть от дальнейших модификаций персистентных ентитей, хотя состояние самих ентитей — естественно будет зависеть. Ну дык, мы состояние-то и не выбирали !
S>Все ясно, как день: хочешь Order по OrderItem — иди в базу лишний раз, получай Order по OrderId.
Если принять идеологию ссылок, то это ничем не будет отличаться от навигации. Более неудобно — да, а семантически — ничем.
Здравствуйте, AndrewVK, Вы писали:
B>> Но первый же виртуальный вызов потребует переноса этого процесса в рантайм, AVK>Виртуальность нужна только при наличии наследования, следовательно вначале надо определится с ним.
Имелось ввиду, что например в таком методе
в компайл-тайме мы не можем даже теоретически определить количество необходимых данных в запросе. Нужно что-то вроде HotDataSpot, что бы генерировать отдельный запрос на каждую реализацию IOrderProcessor.
Здравствуйте, Belsen, Вы писали:
B>А в пределе мечтаний, конечно хотелось бы, что бы количество загружаемых в запросе данных расчитывалось в компайл-тайме анализом кода, который будет эти данные использовать.
Это невозможно ровно потому, что собственно данные и отличаются от кода тем, что имеют свойство меняться в процессе эксплуатации. Редкие случаи, когда это не так, естественно позволяют пользоваться всей мощью статического анализа.
B> Но первый же виртуальный вызов потребует переноса этого процесса в рантайм, а там понятно, что хотелось бы учитывать и вероятность того, понадобятся дополнительные данные или нет, учитывать и стоимость догрузки недостающих данных, и оверхед загрузки неиспользуемых.
Пределом моих мечтаний является такой анализ кода, который позволяет оптимально назначать блокировки.
Ну вот к примеру, если я не делаю в транзакции повторных чтений, то для обеспечения serializable мне вполне достаточно удерживать read locks только на время сканирования. А если делаю — то надо держать локи до последнего чтения.
Современная реляционная СУБД в силу своей клиент-серверной природы ничего не может сказать о предстоящих действиях шального клиента. Поэтому такими вещами рулят разработчик на пару с дба, расставляя хинты и уровни изоляции. А в мегакрутой мегасреде, где весь код доступен еще до момента начала его выполнения, можно и поанализировать.
В теории это все близко к escape-анализу, который то ли собираются, то ли уже применили в Java для принятия решения о размещении объекта в стеке.
B>И тогда ручная загрузка данных станет таким же моветоном, как и ручное управление памятью, и на каком-нибудь форуме устанут повторять, что пытаться обогнать с помощью ручной загрузки оптимизатор в неспецифических случаях практического смысла не имеет
Угу. Уже сейчас порвать промышленную RDBMS хинтами крайне сложно.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Судя по всему, кто хотел что то сказать, тот уже высказался. Посему всем спасибо. Заинтересованные в дальнейшей проработке концепции пишите мне на avk (собака) rsdn.ru.
Здравствуйте, AndrewVK, Вы писали:
AVK>Судя по всему, кто хотел что то сказать, тот уже высказался. Посему всем спасибо. Заинтересованные в дальнейшей проработке концепции пишите мне на avk (собака) rsdn.ru.
А можно маленькое такое замечание в догоночку... а?
Когда мне говорят про БД я воспринимаю это автоматом как предложение делать одну т туже работу дважды — рисовать таблицы и классы, а потом играть в синхронизацию моделей.
Если вам хотябы в концепции удасться избавить людей от этой утомительной игры — то будет большой респект.
Здравствуйте, WoldemaR, Вы писали:
WR>Когда мне говорят про БД я воспринимаю это автоматом как предложение делать одну т туже работу дважды — рисовать таблицы и классы, а потом играть в синхронизацию моделей. WR>Если вам хотябы в концепции удасться избавить людей от этой утомительной игры — то будет большой респект.
Об этом речь уже шла. Кое какие наметки есть в заготовке концепта, который я рассылал заинтересованным лицам. Вобщем то идея вполне логичная — LINQ устраняет промежуток между типами кортежей БД и типами программы, хотелось бы аналогичного механизма и в случае метаданных.
Здравствуйте, AndrewVK, Вы писали:
AVK>Судя по всему, кто хотел что то сказать, тот уже высказался. Посему всем спасибо. Заинтересованные в дальнейшей проработке концепции пишите мне на avk (собака) rsdn.ru.
Безумству храбрых поем мы песню.
Что-то я думал что все заглохло и пропало. Обычно когда человек замысливал такую вещь, его тут же отсылали к литературе и готовым образцам. После чего он как-то пропадал. Не ожидал.
Здравствуйте, AndrewVK, Вы писали:
Кстати, о птичках. Давно я не смотрел на DB4O. Вроде как и LINQ у них ужо есть... И репликация с RDBMS реализована для Occaisonally Connected модели...
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Кстати, о птичках. Давно я не смотрел на DB4O. Вроде как и LINQ у них ужо есть...
Я бы это Linq не назвал(блин, назвали бы внутренний язык DLinq как нибудь по другому. Чтобы идентифицировать легче). Там SODA.
Вообще же там три языка.
1. QBE — Query By Example. Язык на основе прототипирования.
2. SODA.
3. Native QueryЗдесьЗдесь Эти запросы пытается в свою очередь пытаются перевести в SODA и в таком виде оптимизировать и выполнить. А возможности SODA достаточно ограничены. Что не смог, то выполняет в явном виде с полным инстанцированием.
SODA — это не DLINQ. Джоинов там нет. Точнее все join могут выполняться только по предопределенным связкам. Что особенно не нравится — нет возможностей инстанцирования по умолчанию абстрактных классов и интерфейсов. Групповых операций тоже нет(что с их системой инстанцирования, неудивительно).
PS. Кстати, майский Linq уже вышел.
Здравствуйте, GlebZ, Вы писали:
GZ>3. Native QueryЗдесь
GZ> Здесь Эти запросы пытается в свою очередь пытаются перевести в SODA и в таком виде оптимизировать и выполнить. А возможности SODA достаточно ограничены. Что не смог, то выполняет в явном виде с полным инстанцированием.
Совершенно верно. Именно так работает DLinq. Какая разница, в какой таргет язык переводится предикат??? GZ>SODA — это не DLINQ. Джоинов там нет. Точнее все join могут выполняться только по предопределенным связкам. Что особенно не нравится — нет возможностей инстанцирования по умолчанию абстрактных классов и интерфейсов. Групповых операций тоже нет(что с их системой инстанцирования, неудивительно).
Хы-хы. Иначе б жить было скучно. GZ>PS. Кстати, майский Linq уже вышел.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Совершенно верно. Именно так работает DLinq. Какая разница, в какой таргет язык переводится предикат???
Вообще-то нет. У DLinq явно выделены комманды которые может распарсить и воспользоваться, и которые не может. Посмотри последнюю документашку по DLinq. Правда документации по expression tree так и нету.
GZ>>SODA — это не DLINQ. Джоинов там нет. Точнее все join могут выполняться только по предопределенным связкам. Что особенно не нравится — нет возможностей инстанцирования по умолчанию абстрактных классов и интерфейсов. Групповых операций тоже нет(что с их системой инстанцирования, неудивительно). S>Хы-хы. Иначе б жить было скучно.
Этто точно.