Pull to refresh
18
0
Давидич Алексей @david_off

User

Send message
Спасибо, рад что был полезен.
Пример, 1 в 1 повторяющий нашу ситуацию я не стал приводить здесь ибо он бы очень сильно отвлёк от сути. И то что я привел, похоже не самая удачная аналогия. Если же говорить о конкретно нашей проблеме, то нам нужно было проверять уникальность строк, по критерию, который нужно вычислять на основе JOIN-а нескольких таблиц. Поэтому и пришлось использовать скалярную функцию.
Если под «этот текст» имелись ввиду определения, которые я дал для каждого уровня, то вы правы. Я думаю во всех источниках по данной теме будет сходство. Ведь не зря они на одну и ту же тему.
А если главной целью вопроса было «зачем копипастить википедию», то отвечу. В самой статье я говорил, что успехом понимания уровней является практическое понимание побочных эффектов. Именно в приведённых скриптах я видел ценность своей статьи.
При беглом поиске в википедии я смог найти эту статью, скрипты которой отличаются от моих своей абстрактностью. Т.е. их нельзя просто запустить и воочую лицезреть отличия поведения, при задании различного уровня изоляции.
Почитал, некоторые ваши коменты даже улыбнули. Вот сначала вы пишете:
«Я эту главу ещё не читал, но уже готов осуждать! ...»

И сразу же за ним (как я понимаю, после прочтения):
Неплохая глава.


У меня сложилось впечатление, что первоочередным для вас было не получение пользы от прочтения, а повышение ЧСВ.

Видно, что вы в теме достаточно хорошо разбираетесь, но подача ваших коментариев мне показалась излишне критичной. Спасибо вам, конечно, за поиск недочётов (некоторые опечатки и неточности), но уверен, что критику можно сделать чуть-более конструктивной и менее эмоциональной. Зная, как сложно пишутся подобные труды и сколько раз они меняются по ходу написания, готов приклонится, что автор всё-таки нашёл время и закончил книгу в том виде, как она есть.
Зная автора лично, могу сказать, что он всегда отрыт к обсуждению. И это не будет упёртое отстаивание своей точки зрения. Если он не прав, то с радостью это признает (все мы учимся и рады узнать что-то новое). Но в большинстве случаев он достаточно хорошо может аргументировать свою точку и скорее всего донести свою мысль так, что вы с ним согласитесь. Так что рекомендую написать ему на почту или в блог (в блоге он тоже писал про выход этой книги)

Прочитав практически всю книгу могу сказать следующее.
Самое главное отличие от любой другой книги в том, что здесь не ставится за цель просто рассказать о патерне.
Автор всегда старается достаточно подробно и взвешенно подать каждый патерн, что бы их использование не было «просто ради использования».
Кроме того, уделяется не мало внимания правильному дизайну и проектированию. Даже есть отдельный раздел, который расматривает принципы SOLID.
Рассматривается обилие трюков специфичных для С#, которые помогут по другому посмотреть на реализацию патернов.
Я более чем уверен что «Gang of four + примеры на С#» это далеко не то, что вы сможете получить от этой книги.
Рискну предположить что это был не прощёт, а тщательно продуманное решение. Ведь за гибкостью и большим количеством возможностей обычно таится сложность.
При разработке языка / платформы не пытались сделать что-то, подходящее на все случаи жизни. Они старались сделать то, что подойдёт для большинства и будет максимально удобным.
Возможно когда-то это будет добавлено, но до сегоднешнего дня находились более интересные направления развития. Например, TPL, async/await, Roslyn и т.п.
Также хочу вспомнить старую проблему нулевых ссылок (подробней здесь). Не буду утверждать, что сравнение 100% адекватное, но это пример того, как дополнительная возможность может порождать больше зла, чем добра. Вроде уже даже активно обсуждается добавление в C# инструментов, которые позволять создавать ссылочные типы, но не иметь возможности хранить NULL в ссылочной переменной. Т.е. я намекаю на то, что выбирая между добавлением описанной вами фичи и её отсутсвием, Microsoft, взвесив все за и против, решила её не реализовывать, боясь породить больше зла. Верни время назад, они бы скорее всего не реализовывали возможность хранения NULL значний в ссылочных переменных.
Мысли такие потому, что часто читал статьи Эрика (Eric Lippert), в которых он рассказывал, как MS скурпулёзно подходит к выбору фич и возможностей языка и платформы. Он многократно на пальцах объяснял, как добавление какой-то «всеми долго желанной» фичи на самом деле не имеет смысла, по причине «большего зла».
Походу я не сразу понял проблему, которую вы описывали. Но тепрь надеюсь смогу ответить на заданный вопрос :).
У MemoryCache будет проблема, о которой вы спрашиваете. Внутри данные хранятся во множестве объектов типа Hashtable. Т.е. никаких трюков с сериализацией и утаивания существующих объектов от GC не происходит.
Может быть я невнимательно читал и статья совсем про другое

Статья действительно немного о другом. Я не ставил за цель открыть все подробности реализации MemoryCache. У меня было две цели:
1) дать вводную информацию про что такое кеш и некоторые советы по тому как правильней организовать кеширование
2) отрыть некоторые грабли, на которые обязательно наткнёшься при начале использования MemoryCache.

что происходит с инвалидированными объектами

Попробую ответить, основываясь на представлений о работе CLR и на беглом исследовании исходного кода (т. к. документация об этих вещах умалчивает).
Сам класс не старается управлять памятью напрямую, используя неуправляемый (unmanaged) код. Его основной задачей связанной с памятью является гарантирование, что ссылки на элементы будут удалены из кеша согласно «политикам протухания (expiration)», а так же в случае достижения лимитов по разрешённой памяти. На этом его работа считается оконченной и в игру вступает Garbage Collector. А тот уже удаляет объекты согласно алгоритму, основанном на поколениях. И получается, что если элемент в кеше действительно пережил две сборки, то он будет во втором поколении и может залипнуть там на некоторое время. Ведь как вы правильно заметили, то мы работаем в среде с автоматическим управлением памяти, и получается что это уже особенность среды (как она управляет памятью), а не конкретной реализации кеша.
Вообще, если задуматься, как это можно было бы реализовать иначе, то мне в голову приходят только крайне сложные решения:
— либо всё на unmanaged коде
— либо как-то так, что бы класс управлял логикой работы GC. Например, оставлял объекты в специальном поколении, которое можно было бы проверить, после того, как кеш удалил объекты. Но насколько я знаю, пока GC не даёт такой возможности и специально для класса MemoryCache его не будут наделять такими возможностями.
По итогу, если хотим избежать задержки, то мы должны перенимать на себя заботу о своевременной очистке памяти. Но это уже попахивает написанием своего GC. Поэтому я бы просто смерился, что будет некая задержка, прежде, чем ненужные значения из кеша фактически удалятся из памяти.
И последнее. Я думаю, что перерасход памяти и задержка не должны быть очень большими. Если у нас в приложении активно что-то кешиться, то наши 0-е и 1-е поколения будут всегда быстро заполняться и приводить к сборке во 2-м поколении. Так что по факту overhead должен быть минимальным.
Вообще, написав такой долгий момент, думаю есть смысл сделать отдельный пост про «что такое кеш», что есть готовое в .Net и как этим пользоваться. Надеюсь не полениться и написать об этом в ближайшем будущем
Для начала, хотелось бы разобраться что такое кеш. Ведь реализация на основе ConcurrentDictionary это не совсем кеш. Одним из важных свойств любого кеша является возможность быть ограниченным по максимальному объёму занимаемой памяти. Для Dictionary-like реализаций это далеко не просто сделать. Можно конечно условно задать максимальное количество элементов в словаре, но мы всё равно можем добавить небольшое кол-во тяжёлых объектов и в итоге такая реализация будет попахивать утечкой памяти. Поэтому ответ будет скорее всего зависеть от ваших целей.
Если вы хотите гарантировать, что операция получения каждого дорогостоящего ресурса будет произведена не более одного раза (получили и положили в словарь), то вам вообще кеш не нужен и переходить на него не надо никогда.
Если всё-таки, ваша цель иметь кеш, то в первую очередь он должен быть реализован как кеш. Благо начиная с .Net 4.0 у нас появились ObjectCache и его прямой потомок MemoryCache, которые очень облегчают жизнь разработчика и дают готовую In-memory реализацию правильного кеша.
Далее, если мы говорим о переходе с MemoryCache на In-Role Cache (будь то co-located или dedicated), то преимуществ особо я не могу придумать. Максимум что приходит в голову, это более удобное планирование ресурсов (мы можем контролировать максимально возможный объём занимаемой памяти и размещение его в топологии нашей системы через конфигурационный файл нашего Cloud Service-a). Ещё, как по мне, декларативно выделенный кеш в виде отдельного компонента, выглядит более логичнее и проще для правильного конфигурирования. Так же, это может быть маленький шажочек на пути к горизонтальному масштабированию. Ведь если мы в Azure, то наверняка мы должны быть готовы к резкому увеличению нагрузки на систему и тогда, увеличивая количество экземпляров наших WebRole, мы должны иметь возможность сделать кеш общедоступным всем экземплярам. Иначе каждая роль будет иметь свой кеш, и ценность такого кеша будет падать (мы будем всегда читать более одного раза одно и тоже значение, даже если само значение только что вычитано, но наш балансировщик нагрузки направит запросы разным экземплярам WebRole), В случае с MemoryCache, хранимого в одной роли, добиться общедоступности будет сделать не просто.
Переход на Redis может так же дать какой-то выигрыш производительности за счёт специфики реализации самого Redis, плюс открыть возможности реализации например Publisher-Subscriber механизма.
Т. е. ещё раз повторюсь, всё зависит от того, что вы хотите в итоге получить и очень сложно дать дельный совет по вашему вопросу, не будучи знакомым с особенностями проекта.
Да, не всегда мой русский является исконно русским. Сегодня многие английские слова так плотно входят в обиход, что далеко не сразу находятся русские аналоги. Но главное не скатываться до абсурда, как это было у меня в институте. Одного человека заставили на плакатах по защите диплома переводить слово cookies и на них жирно красовались слова «печеньки» и производные от них.
Согласен, что судя по ценам, которые мы видим на сайте, то 6Гб кеш можно соорудить из двух D2 linux серверов и сэкономить около $80 в месяц; аналог 2,5Гб кеш из двух D1 серверов, даст экономию $40 в месяц (цифры для стандарт версии). Но, нужно учитывать несколько важных моментов. Искользуя Azure Redis Cache у вас есть ряд приятных плюшек, таких как: мониторинг, настройки прав доступа, развёртывание в 3 клика и тп. Если посчитать время, которое потребуется админу на поднятие серверов и попытку соорудить что-то подобное возможностям Azure, то может оказаться, что игра не стоила свечь. И каждый раз когда нужно что-то промастабировать, изменить и т.п. мы опять будем бежать к админу и иметь завязку на человеческий фактор, который может болеть, быть занят и т.п. Так что тут решает каждый сам, что его важнее, сэкономить 50 баксов и потерять удобство и SLA или всё же переплатить и пользоваться всеми бенефитами инфраструктуры Azure.
На самом деле не забыл, а умышленно пропустил. У меня с ним опыта практического очень мало. Для себя смотрел, но толково рассказать бы не смог, поэтому решил не портить статью куском «а бы что нибудь рассказать» и решил оставить это для других, например для Вас. Думаю Вы сможете написать статью, а на мою статью разрешаются сослаться, как на вступительную часть :).
Перепроверил и не смог получить поведение с DROP/CREATE. Возможно я проверял на другой версии MS SQL Server, но мои результаты следующие: у меня была таблица Table с колонкой LastName; переименовал колонку в Surname и добавил новую колонку NewColumn; в результирующем миграционном скрипте вижу:
--...
EXECUTE sp_rename @objname = N'[dbo].[Table].[LastName]', @newname = N'Surname', @objtype = N'COLUMN';
--...
ALTER TABLE [dbo].[Table]
    ADD [NewColumn] INT NULL;
--...


Встречные вопросы:
1) На какой версии сервера проверяли Вы?
2) Какие именно вы проверяете скрипты? Ведь то что в проекте это не миграционные скрипты.
3) Вы для переименовки пользовались функцией SQL-> Refactor-> Rename?
Для каждого проекта генерится отдельный DACPAC. Так как один проект представляет одну базу, я думаю в решении Dim0FF будут различные пакеты для каждой базы.
Уважаемый, lair. Как я уже сказал, я не ставлю за цель убедить вас и ваших коллег в том, что бы вы пришли к использованияю SSDT. Каждый волен принимать решение по своему усмотрению. Если вы искренне верите, что SSDT вам будет больше мешать, чем помогать, то я не стану доказывать обратное. Наш с вами диалог понемногу начинает мне напоминать известную картинку, поэтому с Вашего позволения, я не буду продолжать это обсуждение и оставлю за собой право верить, что всё-таки найдутся читатели хабра, которым данный иструмент больше поможет, чем помешает и они будут рады узнать о его существовании.
Умеренное — это сколько? Час, два, десять?

Я уже писал что конкретных цифр не могу привести, но внутри одной базы рискну предположить что это будут секунды или десятки секунд, но ни как не часы. Всё-таки Resharper делает похожие вещи в C# коде и у меня был опыт работы с проектами, в которых были десятки тысяч файлов.

«Невозможно» — это «мы пробовали, и у нас не получилось», или «мы даже не пробовали»?

Скорее пробывали и было крайне не удобно. Тесты могут спасти и показать где проблема, но я предпочту сделать все необходимые изменения и запуская тесты, просто убеждаться, что я ничего не поломал, вместо того, что бы видеть, где нужно починить.

И как же с ними работать тогда?

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

Мы с ними боремся тестами.

SSDT не отменяют и не запрещают использование тестов. Наоборот, они упрощают их создание, чем в свою очередь способсвуют повышению степени покрытия тестами (легче тестить — можно за то же время больше покрыть). Об этот есть отдельный раздел в статье.

PS: я не претендую на то, что SSDT должны заместить все имеющиеся наработанные практики и быть панацеей для всего. Я просто хочу сказать, что они могут упросить или решить ряд ежедневных проблем, которые без подобного иструмента решаются гораздо сложнее.
Рефакторинг и построение изменений по десяткам тысяч объектов?

Наверняка на такой базе процесс переименования будет проходить дольше, чем на нашей. Но всё равно он будет выполнен успешно и за умеренное время. Конретных цифр не могу привести, но склонен верить, что это будет не медленней, чем при использовании аналогичных иструментов (например SQL Bundle от Red Gate). Вообще на таких размерах думаю без использования чего-то подобного просто невозможно вести разработку и эти инструменты — MUST HAVE.

А как же согласованные изменения? А отслеживание зависимостей между БД?

Если вы используюте механизмы Linked Server или его аналоги (OPENDATASOURCE и OPENROWSET) и в хранимках или вьюхах одной базы на прямую задействованы объекты других баз (таблицы, вьюхи, хранимки), то конечено автоматически рефакторинг это не исправит. Но с другой стороны, если у вас действительно всё так организовано и часто меняются таблицы, от которых зависят внешние базы данных, то тут уже проблема подхода. Как по мне, не стоит напрямую использовать эти объекты из внешних баз, если они могут меняться.
В свою очередь, будет интересно узнать, как вы сейчас боретесь с этими проблемами и есть ли какой альтернативный подход?
Признаюсь, наша база не отличается слишком большим количеством объектов и объёмом данных (проект только начался). Но я не вижу причин, по которым этот подход может не сработать, если размер базы увеличится. Касательно поддержки «20+» — инструмент не даёт ни чего специального. В вашем случае я бы создал solution с отдельными Database проектами. Это позволит получить отдельный DACPAC для каждой базы и поставлять изменения по необходимости в каждую базу отдельно.

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Date of birth
Registered
Activity