Comments 15
Вот мне интересно, как думают люди которые пишут про "низкоуровневый SQL".
В реальности SQL, как правило сильно выше уровнем чем тот код, который его использует. SQL реально абстрагирует клиентов от того как хранилище в конкретной БД реализовано. А вот клиентский код, как правило, "прибит гвоздями" к представлению данных в памяти процесса.
LINQ, пожалуй, первая попытка подтянуть средства современных языков до уровня SQL. Остальные же ОРМ предлагают нам вместо относительно универсального SQL, привязанное к конкретному языку кривое подмножество этого самого SQL. Ну и кучу разных веселых проблем в качестве бонуса :(
Код SQL выше уровнем, чем клиентский код его использующий? Это как? Поясните.
Организацию данных в памяти приходится учитывать при реализации алгоритмов их обработки. То есть, мы на клиенте сразу решаем, что, например, идем по списку сотрудников, подтягиваем для каждого "расшифровку" статуса из рядом лежащей мапы и название отдела из еще одной (заранее сформированной) мапы. При этом может получится так, что в некоторых случаях (например, в случае фильрации по отделу) быстрее будет не перебирать всех сотрудников а иметь дополнительную мапу сотрудников по отделам и вытаскивать сотрудников сразу из нее - а мы уже прибили гвоздями конкретный алгоритм, завязанный на нашу структуру данных в памяти.
В случае с SQL, сервер сам решает как ему наиболее эффективно получить нужные данные по сотрудникам, обходить ему весь список или не стоит, и т.д. Понятно, что в случае с БД иногда приходится включать голову и создавать индексы, но при этом, как минимум, мы не рискуем ничего сломать в плане состава получаемых данных.
Ну так это к SQL коду непосредственно отношения не имеет. Вы здесь описываете частный случай денормализации данных, т.е. создать рядом мапу(ы) из нормализованных полей данных для ускорения поиска по частому конкретному запросу. Это скорее к теории отношений БД: как их правильно составлять и проектировать размещение данных. Никто ведь не заставляет клиентский код прибивать гвоздями к этим мапам: их можно агрегировать в соответствующие вьюхи и использовать через ORM как обычные таблицы. Вот SQL код во вьюхах и пусть оптимизирует сама БД, она и статистику соберет по запросам. И у вас выходит, что в клиентском коде зашито знание как эти данные хранятся в БД. А клиентскому коду по-хорошему знать об этих приседаниях не надо.
Другое дело, что от этого легко уйти на словах, а на практике все не так радужно. В наших проектах тоже активно используется EF и нет-нет да и прорываются запросы на голом SQL (кастомные отчеты или хитрые запросы, будь они не ладны). Те же хранимки хочешь не хочешь содержат в себе часть бизнес-логики т.е. знают как собирать данные для ответа клиенту.
Каждый раз приходя на очередной проект и видя развесистый EF спрашиваю местных: в чем сила брат? в чем преимущество использования здесь ORM'а? И обычно первым же ответом идет чтобы легче переехать на другую СУБД "если что". Причем это самое "если что" не уточняется и не случалось чуть ли не десятилетиями. Для меня же это в первую очередь продуманная инфраструктура, удобный генератор миграций, валидация моделей классов, встроенное кеширование и прочие плюшки оптимизаций запросов. Поэтому при всех недостатках ORM'а все же выступлю за его использование. Однако учитывая текущую ситуацию все же раз в пару десятков лет это самое "если что" стреляет. Вот и у нас на горизонте замаячила задача переезда с MS SQL на что-то опенсорсное.
Не совсем так. Я имел ввиду то, как клиент работает с данными у себя в памяти. Клиенту приходится значительно больше внимания уделять тому как данные у него в памяти размещены, какие ему понадобятся вспомогательные стурктуры и т.д. А уж переключить алгоритм выборки в зависимости от условий запроса он никак не может - это всё перекладывается на разработчика, а это, чаще всего, слишком сложно для реализации в конкретном случае.
Именно с этой точки зрения SQL более высокоуровневый - он скрывает сильно больше деталей реализации и избавляет клиентов от большого кол-ва рутины.
На счет встроенной миграции - соглашусь. В мире БД с этим есть проблемы.
На счет кэширования - скорее нет. Пусть лучше будет больше кэша в самой БД чем entity level кэш в ОРМ со всем прилагаемыми проблемами. Просто потому, что проблем с инвалидацией кэшэй в БД я не припоминаю, а вот в ОРМ - вполне себе.
На счет валидации - в целом, фича хорошая - статической типизацией нужно пользоваться. Только, ИМХО, реализовывать это нужно было бы немного по-другому. Но тут стреляет другая проблема мэйнстримовых ЯП, мало кто дает выполнить какой-то свой код на этапе "компиляции" чтобы проверить, что все поля запроса на месте и типы данных у них совместимы с кодом.
А почему выбрали MySQL, после MSSQL, а не PostgreSQL? Там и проблем с типами не было бы, и аналог rowversion есть https://www.postgresql.org/docs/current/ddl-system-columns.html . По мне так MySQL выглядит больше как даунгрейд СУБД в этом плане, если конечно вы осознано выбирали MySQL под очень узкий тип задач.
Mysql неосознанно выбран более десятка лет назад и используется почти во всех наших проектах, так что теперь мы слишком хорошо знаем, как его готовить, чтобы имело смысл переходить на постгрес.
Почему я представляю это вот так? В целом это очень странно..
Почему на рободьяволе реклама пиццы?
Хочется заметить, что в 2011 году мускуль и постгря были совершенно другими базами, и никто не мог предсказать траекторию их развития. У постгрес так вообще тогда были серьёзные проблемы с репликацией, что объективно отпугивало от её использования. А картинка классная, спасибо)
Нужно было взять для перезаливки данных расширение linq2db.EntityFrameworkCore - там легко делается пайплайн из исходной таблицы и вставка в таргет. Вставка присходит быстро и не нужно дополнительных телодвижений.
Приблизительный пример как это могло быть:
using var sourceContext = new MyDbContext(sourceOptions);
using var targetContext = new MyDbContext(targetOptions);
targetContext.BulkCopy(sourceContext.SomeTable.AsNoTracking().AsEnumerable());
targetContext.BulkCopy(sourceContext.SomeOtherTable.AsNoTracking().AsEnumerable());
... // и тд.
Можно сделать обобщенные фукции которые могут заливать инкрементарно или перезапускать заливку если данные в таблице есть, а количество не совпадает.
Также ничего не мешает сериализировать классы в файлы и загружать их если источник недоступен.
На заметку - есть ещё такая удобная визуальная тулза для переноса данных из одной бд в другую - Pentaho Data Integration (вроде бы она же называется Kettle, а сам исполняемый файл Spoon). Вот ссылка на community edition - https://sourceforge.net/projects/pentaho/files/Data Integration/7.1/
В своё время очень помогла при миграции с MS SQL и с Oracle на Postgres. Впрочем она написана на Java и поддерживает любые JDBC драйвера.
Как сменить базу данных, если у вас Entity Framework