Спасибо. Спасибо за поддержку. Всё только начинается. В ближайшие дни нам с тобой предстоит выступить на http://sqlrally2012.ru, приходите или смотрите нас онлайн.
Это как и 30% некая константа, которая зашита в оптимизатор. Но только 30% – это если ограничиваете выборку предикатом с одной стороны, а 9% – это когда указываете некий интервал.
Я тут еще некоторые моменты с константами раскопал, думаю в ближайшее время опубликую заметку.
Доброго дня вам. Меня очень понравился ваша статья. Оно очень детально обсуждает change tracking. У меня вопрос такой – как можно синхронизировать SQL Database (файл mdf) с SQL Sever, так как это делается с помщью чанге тракинг?
Не совсем понял вас. Вы имеете ввиду подключаемый файл mdf в своем проекте Visual Studio? Если да, то например на SQL Server вы можете вручную включить Change Tracking и использовать обычнее его команды, чтобы получать список изменений с сервера. Только придется всю синхронизацию вручную прописывать в коде. А вот если хотите обратную синхронизацию, то сходу сразу не скажу: насколько я помню, это в принципе обычная БД, которая подключаетсяотключается к локальному экземпляру. А вообще использование именно mdf файла в вашем проекте чем мотивировано?
Спасибо за ответ. в моем проекте я использую Service-based Database из за Database Diagram, что бы прeдoвтартить добавление неправильних данных, то есть не связанных(relationship), а также предотвращение удаления связанных данных.
Но тот же SQL Server Compact поддерживает Foreign Keys, но правда там нет диаграмм, хотя мне кажется это не повод делать выбор. Кстати, если уж вы не хотиет использовать Compact Edition, то почему бы на клиенте не реализовать связку SQL Express и ваше приложение, вместо подключаемой базы?
Все верно, на клиенте будет SQL Express и SQL Express будет синхронизовываться в обе стороны с основным сервером. Тогда легко сможете использовать change tracking.
Давайте я поясну. Пишу программу “рабочее место кассира”. Ну вот, есть много касс(клиенты) которие свoи данные, например наменкалатура, палучают из сервера, а обратную синхронизацию отправляют только документы чеков, тоесть продажа. У каждого чека уникальный номер, чтобы на сервере не запутать с чеками из других касс. База виброна SQL Datatabase (Service-based database) о чем я прежне говорил. База данных содаётса и каждая касcа работает нармально в локальном. Остается синхронизировать данные. Change Tracking работает только с Compact SQL(sdf), а тyт нужно синхронизация с файлом mdf.
Change Tracking работает с любой версией, только вот я не уверен, как заставить его работать с Serice-based database. Но т.к. она из себя представляет просто подключаему базу данных, то почему бы вместо нее не использовать SQL Express на клиенте (все равно на клиенте он должен быть установлен для работы service-based database). Далее можно организовать синхронизацию разными способами, в т.ч. и change tracking. Вот только использовать мастеры для его настройки не получится, придется написать процедуры для синхронизации самому и запускать это все во время соединения с главным сервером.
Я написал вот такой класс для синхронизаци, но тут оказалась есть проблема, что кады раз во время синхронизаци я должен буту удалить все синхонируымие таблицы из клиента, чтобы синхронизация работала правильно, этого моон делать когда клиенты полачают данные, но нелезя, когда они отрправлают чеки на сервер. на сервер мы не можем очистить таблица чеков.
using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.SqlServer;
namespace ExecuteExpressSync
{
public class PosSyncAgent
{
private SyncOperationStatistics _syncstat;
private string[] _tablenames;
#region Public Properties
public SyncOperationStatistics DownloadStat
{
get { return _syncstat; }
}
#endregion
public void SetupDBSynchronization(bool includeserverside)
{
var serverConn = new SqlConnection(Serverconnstring);
var clientConn = new SqlConnection(Clientconnstring);
try
{
clientConn.Open();
using (var cmd = clientConn.CreateCommand())
{
foreach (var t in _tablenames)
{
cmd.CommandText = “delete from” + t;
cmd.ExecuteNonQuery();
}
}
var productScope = new DbSyncScopeDescription(“TableForUploads”);
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.UserTypes”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.Users”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.Units”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.ProductsList”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.ProductBarcodes”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.CardTypes”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.CustomersList”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.DiscountCard”, serverConn));
if (includeserverside)
{
var serverProvision = new SqlSyncScopeProvisioning(serverConn, productScope);
if (!serverProvision.ScopeExists(“TableForUploads”))
serverProvision.Apply();
}
var clientProvision = new SqlSyncScopeProvisioning(clientConn, productScope);
if (!clientProvision.ScopeExists(“TableForUploads”))
clientProvision.Apply();
productScope = new DbSyncScopeDescription(“TableForDownloads”);
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.InvoiceHeader”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.InvoiceData”, serverConn));
if (includeserverside)
{
var serverProvision = new SqlSyncScopeProvisioning(serverConn, productScope);
if (!serverProvision.ScopeExists(“TableForDownloads”))
serverProvision.Apply();
}
clientProvision = new SqlSyncScopeProvisioning(clientConn, productScope);
public void DownloadData()
{
if (!TableExists(“ProductsList_tracking”))
{
throw new Exception(“Database synchronization not created.”);
}
var serverConn = new SqlConnection(Serverconnstring);
var clientConn = new SqlConnection(Clientconnstring);
try
{
var syncOrchestrator = new SyncOrchestrator();
var serverProvider = new SqlSyncProvider(“TableForUploads”, serverConn);
var clientProvider = new SqlSyncProvider(“TableForUploads”, clientConn);
syncOrchestrator.LocalProvider = serverProvider;
syncOrchestrator.RemoteProvider = clientProvider;
syncOrchestrator.Direction = SyncDirectionOrder.Upload;
_syncstat = syncOrchestrator.Synchronize();
}
catch (Exception ex)
{
throw new Exception(“Database synchronization error. ” + ex.Message);
}
finally
{
serverConn.Close();
serverConn.Dispose();
clientConn.Close();
clientConn.Dispose();
}
}
public void UploadData()
{
if (!TableExists(“InvoiceData_tracking”))
{
throw new Exception(“Database synchronization not created.”);
}
var serverConn = new SqlConnection(Serverconnstring);
var clientConn = new SqlConnection(Clientconnstring);
try
{
var syncOrchestrator = new SyncOrchestrator();
var serverProvider = new SqlSyncProvider(“TableForDownloads”, serverConn);
var clientProvider = new SqlSyncProvider(“TableForDownloads”, clientConn);
syncOrchestrator.LocalProvider = serverProvider;
syncOrchestrator.RemoteProvider = clientProvider;
syncOrchestrator.Direction = SyncDirectionOrder.DownloadAndUpload;
_syncstat = syncOrchestrator.Synchronize();
}
catch (Exception ex)
{
throw new Exception(“Database synchronization error. ” + ex.Message);
}
finally
{
serverConn.Close();
serverConn.Dispose();
clientConn.Close();
clientConn.Dispose();
}
}
public void Deprovision(bool includeserverside)
{
var serverConn = new SqlConnection(Serverconnstring);
var clientConn = new SqlConnection(Clientconnstring);
try
{
clientConn.Open();
using (var cmd = clientConn.CreateCommand())
{
foreach (var t in _tablenames)
{
cmd.CommandText = “delete from” + t;
cmd.ExecuteNonQuery();
}
}
if (!TableExists(“ProductsList_tracking”))
{
return;
}
var serverSqlDepro = new SqlSyncScopeDeprovisioning(serverConn);
var clientSqlDepro = new SqlSyncScopeDeprovisioning(clientConn);
if (includeserverside)
{
serverSqlDepro.DeprovisionScope(“TableForUploads”);
serverSqlDepro.DeprovisionStore();
}
if (TableExists(“InvoiceData_tracking”))
{
if (includeserverside)
{
serverSqlDepro.DeprovisionScope(“TableForDownloads”);
serverSqlDepro.DeprovisionStore();
}
Прочитал другие посты блога (очень интересно, кстати, спасибо) и вдруг понял, что все в этом мире связаны. Об этом блоге я узнал посмотрев записи докладов с MS DevCon. В прошлом году Дмитрий Костылев звал меня в Лабораторию Касперского на собеседование (увы, тогда я не прошёл), а потом я решал на собеседовании с Романом Дорошенко в НИКС интересные тестовые задания по БД – видимо, твоего авторства (правда, не пошёл к ним работать), и сейчас работаю в бизнес-центре на Вятской, где работал Дима до ухода к Касперскому. И почему только я раньше ничего не слышал об активности sql usergroup в Москве.
Мне тоже кажется, что это быстрее будет и правильнее. Плюс этого метода в том, что он будет выполняться вне процесса SQL Server и его в будущем можно будет даже вынести на отдельный сервер, если будет большой поток данных для преобразования. Сможете легко масштабировать нагрузку. Потому что все методы оптимизации CLR функций, что я видел, заключались в оптимизации непосредственно C# или VB.NET кода, вызывались те или иные методы в зависимости от их производительности. Это очень тонкий тюнинг. А с ETL все гораздо проще. 🙂
Сергей, спасибо за статью. Интересно было понять, будет ли данная система полезна для хранилища для отчётности (SSRS)? Я так понял что пока MS об этом не писали.
Для хранилищ они ее не позиционируют, что собственно ожидаемо. На хранилищах в основном присутствует нагрузка – последовательное чтение. А последовательно считать на максимальной скорости можно и с обычной дисковой подсистемы. Ну и в хранилищах обычно данных очень много, поэтому их и кэшировать не имеет смысла – все равно все не влезет. Для отчетов SSRS кстати отлично можно использовать их встроенное кэширование и предварительный расчет – у меня было много таких реализаций. Ночью, например, заливка новой порции данных, трансформация и т.п., а потом SSRS обновляет отчеты, и к утру все сделано и мгновенно открывается.
Все новинки, кроме пожалуй columnstore clustered индекса для OLTP, даже скучно как-то : ) Насчёт кэширования SSRS не очень понял, там можно расписание настроить, когда отчёт будет кэшироваться или как?
Columnstore это уже немало. 🙂 А для отчётов да, можно указать расписание, когда отчёты будут формироваться и настройки кэширования. Тут долго расписывать нюансы, но однозначно стоит посмотреть на эти настройки. Для тяжёлых и редко обновляемых отчётов самое то.
Нормально, там же совершенно по другому рганизовано хранение. Если рассматривать каждый индекс как отдельную физическую структуру – то ничего не мешает создать 2 копии таблицы – одна с columnstore, а вторую обычную урезанную и создать кластеризованный rowstore индекс. Физически будет одинаково, только если это действительно нужно и дает преимущество. 🙂 Вообще про columnstore в 2014 надо тоже будет серию статей готовить.
Alexey
Копия таблицы это слишком жирно) Получается либо по старому (non-clustered columnstore index), либо секционировать по годам (например) и сделать clustered columnstore index в случае, если основной фильтр будет эта дата.
Я к тому, что любой индекс это фактически копия части данных. Ну а так надо смотреть, что выгоднее будет в итоге учитывая все факторы.
ya.a
Сергей, отличная статья. Но в ней упущен один момент, как собственно понять что эта проблема есть и нужно работать над её решением. Исправляю сей недочёт. Для того что бы понять что у вас некоторые процессоры не используются на всю катушку (спят) нужно установить счетчик “Processor: %Processor Time)” на сутки и посмотреть равномерно ли распределяется нагрузка на процессоры с утра. Если вы увидите что при наступлении нагрузки (как правило с утра) она не равномерно распределена по всем CPU, то скорее всего ваши процессоры после ночного сна, ещё не успели проснуться и в этом виноват режим “Balanced”, попробуйте поставить на “High Perfomance” и проверьте считчики повторно. Примечание: если у вас OLTP система (MAXDOP=1), а не OLAP, то возможно что часть процессоров спит, так как на них нет нагрузки.
Отличный комментарий. В свою очередь поделюсь еще информацией: позже я проводил тесты на IBM BladeCenter и там вообще не играло никакой роли, как были установлены параметры – сама система управляла энергопитанием. И время выполнения тестового запроса там сильно колебалось, в то время как на Supermicro оно было стабильным. Я вообще склоняюсь к факту, что энергопотребление в High Performance надо ставить сразу и без всяких дополнительных тестов. Идеальный вариант – создать OU на уровне AD, включить туда все MS SQL сервера в организации и повесить на OU доменную политику, которая сама рулит уже настройками (и не только энергопотребления).
Да на самом деле набор параметров, значения которых по умолчанию не очень хороши и замена этих значений гарантированно не сделает хуже (на крайний случай просто не будет лучше) достаточно большой. 🙂 Просто они придерживаются консервативного подхода – всегда было такое значение по умолчанию – пусть остается.
Тесты проводились на виртуальной машине, которая была расположена на обычной рабочей машине с Core i7 + SSD. Виртуалке было выделено 4 Гб памяти, но в зависимости от теста для SQL Server размер ограничивался. Там где нужно в тесте было задействовать HDD – я использовал обычный диск на 7200 оборотов – один, но т.к. не было конкурентной нагрузки, то не должно появиться разницы, сколько дисков будет, надо будет только учитывать кэш контроллеров или хранилища. А вот если взять диск на 15000 оборотов, то результаты потенциально могли быть в 1.5-2 раза лучше у тестов с использованием HDD. Я нисколько не претендую на какую-то особую точность в результатах, но мне было интересно провести более-менее реальные тесты и посмотреть. На реальном сервере результаты будут другими, т.к. придется учитывать изменение данных, конкуретную загрузку, зависимость запросов не только от производительности диска, но и процессоров и т.п.
Спасибо. Больше всего интересно, какие IOPS-ы у SSD? Лучше – сразу модель SSD. Мне кажется, эти значения могут оказать серьезное влияние на тесты с SSD.
SSD – Corsair Neutron GTX. Если смотреть на то, что он может, то получаются такие результаты: случайное чтение 8кб блоками с очередью 1 – чуть больше 9000 IOPs, а случайная запись 1кб блоками с очередью 1 – почти 18000 IOPs. Эти показатели здесь, пожалуй, наиболее показательны.
День добрый. Решил использовать Change Tracking в своем проекте, но столкнулся с проблемкой в Visual Studio 2012 нет такого шаблона. Возник вопрос, почему его убрали, и может появилось что-то новое ему на замену?
А почему четвертый быстрее пятого? о_О
Часть BPE все же в оперативной памяти?
Как я понимаю стандартный движок SQL без BPE не умеет держать части индекса в оперативной памяти, только целиком?
Стандартный движок кэширует индексы по страницам, так что спокойно может находится в памяти только часть индекса. Здесь видимо играет роль то, что при чтении с диска Buffer Manager сначала выделяет Buf в памяти, заносит в него страницу и т.п. А если данные уже в BPE, то этой дополнительной нагрузки нет, поэтому и получилось быстрее. Опять же – это мое предположение.
Прочитал на”Харбаре” статью о Вашем замечательном офисе, но вдруг подумалось, – сколько времени эти молодые и успешные менеджеры тратят на дорогу по Московским пробкам и ещё в поисках места для парковки в соседних дворах?
Здравствуйте. В данный момент запись на встречах User Group не делается в принципе, т.к. планируется, что это больше мероприятия для неформальной встречи и общения участников. Обычно время доклада жестко не лимитируется, никто никуда не торопится.
Сходу не скажу, есть ли что-то в этом же духе, кратко и в одном докладе. Стоит поискать на techdays.ru. У англоязычных спикеров можно поискать на YouTube.
Да, что-то я 2008R2 не учел, но если считать его больше как BI-релиз, т.к. по сути изменений там значимых в движке не было (сервис паками они потом практически невилировались полностью), то тенденция есть. Момент спорный, согласен. Смотря как считать. ))
Тестировал на 2014, т.к. тестировать под все версии не представляется возможным. Но я думаю, что на остальных будет также. Если вдруг у вас получатся другие результаты, сообщите мне. Будет крайне интересно.
>>По умолчанию инсталлятор руководствуется следующей формулой: минимум из 2х значений, количество ядер на вашей системе и 8.
Ядер физических или виртуальных?
Еще вопрос
>>Создавать файлов больше, чем у вас ядер в системе, не будет иметь
практического смыла, ввиду того, что одновременно с tempdb не будет
работать больше сессий, чем у вас ядер в системе.
Каждое ядро работает со своим файлом? Или как повезет?
А это не так важно на самом деле. Важно лишь то, есть ли у вас задержки при работе с tempdb в виде latch’ей или задержек по IO. Если есть, надо разбираться, почему они возникают.
>>А это не так важно на самом деле
То есть если есть 64 ядерный сервер, соответственно 64 сессии и все они пишут в один файл tempdb, хотя я их создам ххх.
>>надо разбираться, почему они возникают.
мне кажется в этом случае совсем понятно ПОЧЕМУ
А если они будут писать каждая сессия в свой файл – то будет же лучше.
Вот мне интересно как работает этот механизм
Во-первых, будет зависеть, сколько всего активных сессий на сервере, и сколько из них пишут в tempdb. На то, как их SQL Server раскидает, вы повлиять все равно не сможете. А вот файлов стоит добавлять до тех пор, пока contention не исчезнет. Слишком много их тоже создавать не имеет особого смысла.
Главное достоинство JSON оценят веб-разработчики, так как XML проигрывает тут по всем статьям.
Back-End серверу(например на C#) не потребуется делать преобразование из XML в JSON. Много мелких request от клиента, с постоянным парсингом на back-end и вы получите провал по производительности. Провал XML станет заметным, когда на ваш сервер в 1секунду производится более 1000 обращений от 1000 разных клиентов одновременно.
Напротив, формат JSON из MS SQL 2016 позволяет напрямую передать его сразу во front-end, без каких-либо нагрузок на back-end.
Приятно, что JSON в поле nvarchar(max) можно хранить до 2Гигабайт.
Не думаю, что какому-то прийдет в голову тащить на веб-клиент, более 2Гиг JSON структуры. И главное сжатие JSON, намного будет быстрее чем использование его собрата BJSON.
Начиная с 2012 появилась опция for xml …, BINARY BASE64
Т.е. вот такие конструкции – [почти] эквивалентны:
Select Cast(N’plain_text’ as varbinary(max))
for xml path(”), BINARY BASE64
— Конвертируем значение переменной
declare @value varbinary(max);
set @value = cast(N’plain_text’ as varbinary(max));
select cast(N” as xml).value(‘xs:base64Binary(sql:variable(“@value”))’, ‘varchar(max)’) as [encoded_value];
Привет. Не смог найти упоминаний об ограничении в 128 ГБ в других источниках. Возможно оно легаси или относится к редакции стандарт. Но я смог успешно добавить BPE файл 512 GB на сервере с 192 GB RAM 2014 Enterprise.
“Максимальный поддерживаемый размер оперативной памяти 128 Гб, т.е. обладатели систем с большим размером памяти воспользоваться опцией не смогут. И это довольно неприятный момент, т.к. такой и больший объемы вполне доступны покупателям даже для серверов начального уровня.”
Спасибо. Спасибо за поддержку. Всё только начинается. В ближайшие дни нам с тобой предстоит выступить на http://sqlrally2012.ru, приходите или смотрите нас онлайн.
Ну с 30% понятно откуда она берется. А вот почему 9 % берет, а не не какое то другое число?
Это как и 30% некая константа, которая зашита в оптимизатор. Но только 30% – это если ограничиваете выборку предикатом с одной стороны, а 9% – это когда указываете некий интервал.
Я тут еще некоторые моменты с константами раскопал, думаю в ближайшее время опубликую заметку.
а есть ли у вас видео по олвэйс он или презентация, на сайте пдф не качается, а видео ужасного качества и ничего не видно, embrioz@bk,ru, спасибо
Выслал вам презентацию на электронную почту.
Доброго дня вам. Меня очень понравился ваша статья. Оно очень детально обсуждает change tracking. У меня вопрос такой – как можно синхронизировать SQL Database (файл mdf) с SQL Sever, так как это делается с помщью чанге тракинг?
Не совсем понял вас. Вы имеете ввиду подключаемый файл mdf в своем проекте Visual Studio? Если да, то например на SQL Server вы можете вручную включить Change Tracking и использовать обычнее его команды, чтобы получать список изменений с сервера. Только придется всю синхронизацию вручную прописывать в коде. А вот если хотите обратную синхронизацию, то сходу сразу не скажу: насколько я помню, это в принципе обычная БД, которая подключаетсяотключается к локальному экземпляру. А вообще использование именно mdf файла в вашем проекте чем мотивировано?
Спасибо за ответ. в моем проекте я использую Service-based Database из за Database Diagram, что бы прeдoвтартить добавление неправильних данных, то есть не связанных(relationship), а также предотвращение удаления связанных данных.
Но тот же SQL Server Compact поддерживает Foreign Keys, но правда там нет диаграмм, хотя мне кажется это не повод делать выбор. Кстати, если уж вы не хотиет использовать Compact Edition, то почему бы на клиенте не реализовать связку SQL Express и ваше приложение, вместо подключаемой базы?
Потому что есть много клиентов и один сервер. Кожди клиент должен работать offline а после работы синхронизировать данные с сервером.
Все верно, на клиенте будет SQL Express и SQL Express будет синхронизовываться в обе стороны с основным сервером. Тогда легко сможете использовать change tracking.
Давайте я поясну. Пишу программу “рабочее место кассира”. Ну вот, есть много касс(клиенты) которие свoи данные, например наменкалатура, палучают из сервера, а обратную синхронизацию отправляют только документы чеков, тоесть продажа. У каждого чека уникальный номер, чтобы на сервере не запутать с чеками из других касс. База виброна SQL Datatabase (Service-based database) о чем я прежне говорил. База данных содаётса и каждая касcа работает нармально в локальном. Остается синхронизировать данные. Change Tracking работает только с Compact SQL(sdf), а тyт нужно синхронизация с файлом mdf.
Change Tracking работает с любой версией, только вот я не уверен, как заставить его работать с Serice-based database. Но т.к. она из себя представляет просто подключаему базу данных, то почему бы вместо нее не использовать SQL Express на клиенте (все равно на клиенте он должен быть установлен для работы service-based database). Далее можно организовать синхронизацию разными способами, в т.ч. и change tracking. Вот только использовать мастеры для его настройки не получится, придется написать процедуры для синхронизации самому и запускать это все во время соединения с главным сервером.
Я написал вот такой класс для синхронизаци, но тут оказалась есть проблема, что кады раз во время синхронизаци я должен буту удалить все синхонируымие таблицы из клиента, чтобы синхронизация работала правильно, этого моон делать когда клиенты полачают данные, но нелезя, когда они отрправлают чеки на сервер. на сервер мы не можем очистить таблица чеков.
using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.SqlServer;
namespace ExecuteExpressSync
{
public class PosSyncAgent
{
private SyncOperationStatistics _syncstat;
private string[] _tablenames;
private const string Serverconnstring = @”Data Source=ART-PCSQLEXPRESS;” +
“Initial Catalog=POSDataBase;Persist ” +
“Security Info=True;User ID=sa;Password=111″;
private const string Clientconnstring = @”Data Source=.SQLEXPRESS;” +
@”AttachDbFilename=C:UsersArtDesktopposdb.mdf;” +
“Integrated Security=True;Connect Timeout=30;User Instance=True”;
public PosSyncAgent()
{
_tablenames = new[]
{
” Users; “,
” UserTypes; “,
” ProductBarcodes; “,
” ProductsList; “,
” Units; “,
” DiscountCard; “,
” CustomersList; “,
” CardTypes;”
};
}
#region Public Properties
public SyncOperationStatistics DownloadStat
{
get { return _syncstat; }
}
#endregion
public void SetupDBSynchronization(bool includeserverside)
{
var serverConn = new SqlConnection(Serverconnstring);
var clientConn = new SqlConnection(Clientconnstring);
try
{
clientConn.Open();
using (var cmd = clientConn.CreateCommand())
{
foreach (var t in _tablenames)
{
cmd.CommandText = “delete from” + t;
cmd.ExecuteNonQuery();
}
}
var productScope = new DbSyncScopeDescription(“TableForUploads”);
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.UserTypes”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.Users”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.Units”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.ProductsList”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.ProductBarcodes”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.CardTypes”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.CustomersList”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.DiscountCard”, serverConn));
if (includeserverside)
{
var serverProvision = new SqlSyncScopeProvisioning(serverConn, productScope);
if (!serverProvision.ScopeExists(“TableForUploads”))
serverProvision.Apply();
}
var clientProvision = new SqlSyncScopeProvisioning(clientConn, productScope);
if (!clientProvision.ScopeExists(“TableForUploads”))
clientProvision.Apply();
productScope = new DbSyncScopeDescription(“TableForDownloads”);
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.InvoiceHeader”, serverConn));
productScope.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable(“dbo.InvoiceData”, serverConn));
if (includeserverside)
{
var serverProvision = new SqlSyncScopeProvisioning(serverConn, productScope);
if (!serverProvision.ScopeExists(“TableForDownloads”))
serverProvision.Apply();
}
clientProvision = new SqlSyncScopeProvisioning(clientConn, productScope);
if (!clientProvision.ScopeExists(“TableForDownloads”))
clientProvision.Apply();
}
catch (Exception ex)
{
throw new Exception(“Synchronization configuration error. ” + ex.Message);
}
finally
{
serverConn.Close();
serverConn.Dispose();
clientConn.Close();
clientConn.Dispose();
}
}
public void DownloadData()
{
if (!TableExists(“ProductsList_tracking”))
{
throw new Exception(“Database synchronization not created.”);
}
var serverConn = new SqlConnection(Serverconnstring);
var clientConn = new SqlConnection(Clientconnstring);
try
{
var syncOrchestrator = new SyncOrchestrator();
var serverProvider = new SqlSyncProvider(“TableForUploads”, serverConn);
var clientProvider = new SqlSyncProvider(“TableForUploads”, clientConn);
syncOrchestrator.LocalProvider = serverProvider;
syncOrchestrator.RemoteProvider = clientProvider;
syncOrchestrator.Direction = SyncDirectionOrder.Upload;
_syncstat = syncOrchestrator.Synchronize();
}
catch (Exception ex)
{
throw new Exception(“Database synchronization error. ” + ex.Message);
}
finally
{
serverConn.Close();
serverConn.Dispose();
clientConn.Close();
clientConn.Dispose();
}
}
public void UploadData()
{
if (!TableExists(“InvoiceData_tracking”))
{
throw new Exception(“Database synchronization not created.”);
}
var serverConn = new SqlConnection(Serverconnstring);
var clientConn = new SqlConnection(Clientconnstring);
try
{
var syncOrchestrator = new SyncOrchestrator();
var serverProvider = new SqlSyncProvider(“TableForDownloads”, serverConn);
var clientProvider = new SqlSyncProvider(“TableForDownloads”, clientConn);
syncOrchestrator.LocalProvider = serverProvider;
syncOrchestrator.RemoteProvider = clientProvider;
syncOrchestrator.Direction = SyncDirectionOrder.DownloadAndUpload;
_syncstat = syncOrchestrator.Synchronize();
}
catch (Exception ex)
{
throw new Exception(“Database synchronization error. ” + ex.Message);
}
finally
{
serverConn.Close();
serverConn.Dispose();
clientConn.Close();
clientConn.Dispose();
}
}
public void Deprovision(bool includeserverside)
{
var serverConn = new SqlConnection(Serverconnstring);
var clientConn = new SqlConnection(Clientconnstring);
try
{
clientConn.Open();
using (var cmd = clientConn.CreateCommand())
{
foreach (var t in _tablenames)
{
cmd.CommandText = “delete from” + t;
cmd.ExecuteNonQuery();
}
}
if (!TableExists(“ProductsList_tracking”))
{
return;
}
var serverSqlDepro = new SqlSyncScopeDeprovisioning(serverConn);
var clientSqlDepro = new SqlSyncScopeDeprovisioning(clientConn);
if (includeserverside)
{
serverSqlDepro.DeprovisionScope(“TableForUploads”);
serverSqlDepro.DeprovisionStore();
}
clientSqlDepro.DeprovisionScope(“TableForUploads”);
clientSqlDepro.DeprovisionStore();
if (TableExists(“InvoiceData_tracking”))
{
if (includeserverside)
{
serverSqlDepro.DeprovisionScope(“TableForDownloads”);
serverSqlDepro.DeprovisionStore();
}
clientSqlDepro.DeprovisionScope(“TableForDownloads”);
clientSqlDepro.DeprovisionStore();
}
}
catch (Exception ex)
{
throw new Exception(“Deprovision error. ” + ex.Message);
}
finally
{
serverConn.Close();
serverConn.Dispose();
clientConn.Close();
clientConn.Dispose();
}
}
public string [] TablesRowCounts()
{
var clientConn = new SqlConnection(Clientconnstring);
var tablenames = new string[_tablenames.Length];
try
{
clientConn.Open();
using (var cmd = clientConn.CreateCommand())
{
for (int i = 0; i < _tablenames.Length; i++)
{
cmd.CommandText = "select count(*) from" + _tablenames[i];
using (var sqlrdr = cmd.ExecuteReader())
{
if (sqlrdr.Read())
{
tablenames[i] = _tablenames[i] + "t : " + sqlrdr.GetInt32(0);
}
}
}
}
}
catch (Exception ex)
{
throw new Exception("Tables data getting error. " + ex.Message);
}
finally
{
clientConn.Close();
clientConn.Dispose();
}
return tablenames;
}
public bool TableExists(string tablename)
{
var clientConn = new SqlConnection(Clientconnstring);
try
{
using (var command = new SqlCommand("Select * from " + tablename, clientConn))
{
command.CommandType = CommandType.Text;
clientConn.Open();
command.ExecuteNonQuery();
return true;
}
}
catch{}
finally
{
clientConn.Close();
clientConn.Dispose();
}
return false;
}
}
}
Хорошая штука, у меня только положительные впечатления. Не получилось только заставить по умолчанию по F1 вызываться, хотя судя по настройкам должен.
Сергей, как с вами можно связаться или как можно задать вопрос по планировщику 2008?
Можно по email. sergey@olontsev.ru
Было бы здорово увидеть заметки об Extended Events
Да, в планах есть и даже уже готовы черновики и наброски целой серии.
Прочитал другие посты блога (очень интересно, кстати, спасибо) и вдруг понял, что все в этом мире связаны. Об этом блоге я узнал посмотрев записи докладов с MS DevCon. В прошлом году Дмитрий Костылев звал меня в Лабораторию Касперского на собеседование (увы, тогда я не прошёл), а потом я решал на собеседовании с Романом Дорошенко в НИКС интересные тестовые задания по БД – видимо, твоего авторства (правда, не пошёл к ним работать), и сейчас работаю в бизнес-центре на Вятской, где работал Дима до ухода к Касперскому. И почему только я раньше ничего не слышал об активности sql usergroup в Москве.
Да уж. 🙂 Мир действительно очень тесен, не ожидал. Кстати, в ближайшее время планируется несколько встреч User Group, буду делать анонсы в блоге.
Спасибо.
Pingback: Генерация скриптов для создания и удаления объектов SQL Server и с помощью Powershell | Олонцев Сергей
Забрал, спасибо.
Сергей, а есть материал(статья, видео и проч), которые вы порекомендовали бы по теме правильного написания CLR Table-valued functions?
Алексей, а в каких случаях планируете их использовать, если не секрет?
Парсинг строк из таблицы с большим текстовом полем в другую таблицу в структурированном виде.
А это разовая операция планируется или на регулярной основе? Насчет применения SSIS не думали для этого?
Регулярная. Script Transform в смысле? Ну в принципе тоже вариант.
Мне тоже кажется, что это быстрее будет и правильнее. Плюс этого метода в том, что он будет выполняться вне процесса SQL Server и его в будущем можно будет даже вынести на отдельный сервер, если будет большой поток данных для преобразования. Сможете легко масштабировать нагрузку. Потому что все методы оптимизации CLR функций, что я видел, заключались в оптимизации непосредственно C# или VB.NET кода, вызывались те или иные методы в зависимости от их производительности. Это очень тонкий тюнинг. А с ETL все гораздо проще. 🙂
Ок, буду пробовать)
Буквально сегодня Дмитрий Короткевич опубликовал хорошую статью: http://aboutsqlserver.com/2013/07/22/clr-vs-t-sql-performance-considerations/
Сергей, спасибо за статью. Интересно было понять, будет ли данная система полезна для хранилища для отчётности (SSRS)? Я так понял что пока MS об этом не писали.
Для хранилищ они ее не позиционируют, что собственно ожидаемо. На хранилищах в основном присутствует нагрузка – последовательное чтение. А последовательно считать на максимальной скорости можно и с обычной дисковой подсистемы. Ну и в хранилищах обычно данных очень много, поэтому их и кэшировать не имеет смысла – все равно все не влезет. Для отчетов SSRS кстати отлично можно использовать их встроенное кэширование и предварительный расчет – у меня было много таких реализаций. Ночью, например, заливка новой порции данных, трансформация и т.п., а потом SSRS обновляет отчеты, и к утру все сделано и мгновенно открывается.
Все новинки, кроме пожалуй columnstore clustered индекса для OLTP, даже скучно как-то : ) Насчёт кэширования SSRS не очень понял, там можно расписание настроить, когда отчёт будет кэшироваться или как?
Columnstore это уже немало. 🙂 А для отчётов да, можно указать расписание, когда отчёты будут формироваться и настройки кэширования. Тут долго расписывать нюансы, но однозначно стоит посмотреть на эти настройки. Для тяжёлых и редко обновляемых отчётов самое то.
Сергей, а если в таблице Clustered Columnstore Index, к ней можно создать B-tree non-clustered index или нет? Я всё никак не доберусь проверить)
Если есть Clustered Columnstore, то других индексов добавить на таблицу нельзя.
Вот это очень печально конечно : (
Нормально, там же совершенно по другому рганизовано хранение. Если рассматривать каждый индекс как отдельную физическую структуру – то ничего не мешает создать 2 копии таблицы – одна с columnstore, а вторую обычную урезанную и создать кластеризованный rowstore индекс. Физически будет одинаково, только если это действительно нужно и дает преимущество. 🙂 Вообще про columnstore в 2014 надо тоже будет серию статей готовить.
Копия таблицы это слишком жирно) Получается либо по старому (non-clustered columnstore index), либо секционировать по годам (например) и сделать clustered columnstore index в случае, если основной фильтр будет эта дата.
Я к тому, что любой индекс это фактически копия части данных. Ну а так надо смотреть, что выгоднее будет в итоге учитывая все факторы.
Сергей, отличная статья. Но в ней упущен один момент, как собственно понять что эта проблема есть и нужно работать над её решением. Исправляю сей недочёт. Для того что бы понять что у вас некоторые процессоры не используются на всю катушку (спят) нужно установить счетчик “Processor: %Processor Time)” на сутки и посмотреть равномерно ли распределяется нагрузка на процессоры с утра. Если вы увидите что при наступлении нагрузки (как правило с утра) она не равномерно распределена по всем CPU, то скорее всего ваши процессоры после ночного сна, ещё не успели проснуться и в этом виноват режим “Balanced”, попробуйте поставить на “High Perfomance” и проверьте считчики повторно. Примечание: если у вас OLTP система (MAXDOP=1), а не OLAP, то возможно что часть процессоров спит, так как на них нет нагрузки.
Отличный комментарий. В свою очередь поделюсь еще информацией: позже я проводил тесты на IBM BladeCenter и там вообще не играло никакой роли, как были установлены параметры – сама система управляла энергопитанием. И время выполнения тестового запроса там сильно колебалось, в то время как на Supermicro оно было стабильным. Я вообще склоняюсь к факту, что энергопотребление в High Performance надо ставить сразу и без всяких дополнительных тестов. Идеальный вариант – создать OU на уровне AD, включить туда все MS SQL сервера в организации и повесить на OU доменную политику, которая сама рулит уже настройками (и не только энергопотребления).
Microsoft в рамках программы Microsoft RAS (Premier Support) советует ставить в High Perfomance. 🙂
Основы телепатии изучили видимо ))
Да на самом деле набор параметров, значения которых по умолчанию не очень хороши и замена этих значений гарантированно не сделает хуже (на крайний случай просто не будет лучше) достаточно большой. 🙂 Просто они придерживаются консервативного подхода – всегда было такое значение по умолчанию – пусть остается.
Сергей, укажите пожалуйста характеристики дисков и памяти для полноты картины.
Тесты проводились на виртуальной машине, которая была расположена на обычной рабочей машине с Core i7 + SSD. Виртуалке было выделено 4 Гб памяти, но в зависимости от теста для SQL Server размер ограничивался. Там где нужно в тесте было задействовать HDD – я использовал обычный диск на 7200 оборотов – один, но т.к. не было конкурентной нагрузки, то не должно появиться разницы, сколько дисков будет, надо будет только учитывать кэш контроллеров или хранилища. А вот если взять диск на 15000 оборотов, то результаты потенциально могли быть в 1.5-2 раза лучше у тестов с использованием HDD. Я нисколько не претендую на какую-то особую точность в результатах, но мне было интересно провести более-менее реальные тесты и посмотреть. На реальном сервере результаты будут другими, т.к. придется учитывать изменение данных, конкуретную загрузку, зависимость запросов не только от производительности диска, но и процессоров и т.п.
Спасибо. Больше всего интересно, какие IOPS-ы у SSD? Лучше – сразу модель SSD. Мне кажется, эти значения могут оказать серьезное влияние на тесты с SSD.
SSD – Corsair Neutron GTX. Если смотреть на то, что он может, то получаются такие результаты: случайное чтение 8кб блоками с очередью 1 – чуть больше 9000 IOPs, а случайная запись 1кб блоками с очередью 1 – почти 18000 IOPs. Эти показатели здесь, пожалуй, наиболее показательны.
День добрый. Решил использовать Change Tracking в своем проекте, но столкнулся с проблемкой в Visual Studio 2012 нет такого шаблона. Возник вопрос, почему его убрали, и может появилось что-то новое ему на замену?
А почему четвертый быстрее пятого? о_О
Часть BPE все же в оперативной памяти?
Как я понимаю стандартный движок SQL без BPE не умеет держать части индекса в оперативной памяти, только целиком?
Стандартный движок кэширует индексы по страницам, так что спокойно может находится в памяти только часть индекса. Здесь видимо играет роль то, что при чтении с диска Buffer Manager сначала выделяет Buf в памяти, заносит в него страницу и т.п. А если данные уже в BPE, то этой дополнительной нагрузки нет, поэтому и получилось быстрее. Опять же – это мое предположение.
почему именно 8 процентов? и где их можно смотреть?
Артур, такой объем просто влезал. Смотреть можно через системное представление sys.dm_os_buffer_descriptors
Сергей, спасибо, всё прошло отлично : ) А будет рассылка с материалами докладов (презентации)?
Алексей, все презентации будут доступны для скачивания по следующей ссылке в течение 1-2 недель: http://sqlsaturday.com/261/schedule.aspx
Алексей, все материалы будут опубликованы по следующей ссылке в течение 1-2 недель. http://sqlsaturday.com/261/schedule.aspx
Спасибо, полезная информация.
Для расчета stdev требуется чтение данных два раза?
Есть пример как в оракле сделать то же самое?
Увы, с Oracle не работаю.
кажется, в начале перепутаны местами формулы
Да, Вы правы! Только не сами формулы, а их sql-названия
Прочитал на”Харбаре” статью о Вашем замечательном офисе, но вдруг подумалось, – сколько времени эти молодые и успешные менеджеры тратят на дорогу по Московским пробкам и ещё в поисках места для парковки в соседних дворах?
Подскажите пожалуйста их администраторам или во внутренней сети, что есть решение этой проблемы: http://www.kvadroom.ru/flat_arenda/object_80796735.html
Добрый день! А есть ли запись этого семинара ? Или записей с этого мероприятия не существует ?
Здравствуйте. В данный момент запись на встречах User Group не делается в принципе, т.к. планируется, что это больше мероприятия для неформальной встречи и общения участников. Обычно время доклада жестко не лимитируется, никто никуда не торопится.
Ясно, спасибо. Очень обидно. Может что то подобное есть у других докладчиков ? Я про “Диагностика проблем в SQL Server, практический подход”.
Сходу не скажу, есть ли что-то в этом же духе, кратко и в одном докладе. Стоит поискать на techdays.ru. У англоязычных спикеров можно поискать на YouTube.
Спасибо! Поищу. Но к сожалению, пока не могу в английский.
Хорошо что все фиксы на 2012 и 2014 уже вышли : )
Насчёт сокращения циклов релизов не согласен. 2008R2 вышла 21 апреля 2010, 2012 – 6 марта, 2014 – 1 апреля. Так что примерно одинаково.
Да, что-то я 2008R2 не учел, но если считать его больше как BI-релиз, т.к. по сути изменений там значимых в движке не было (сервис паками они потом практически невилировались полностью), то тенденция есть. Момент спорный, согласен. Смотря как считать. ))
Спасибо! Полезный материал
Сергей, а такая ситуация на всех версиях SQL Server-а? На какой версии вы проводили исследование?
Тестировал на 2014, т.к. тестировать под все версии не представляется возможным. Но я думаю, что на остальных будет также. Если вдруг у вас получатся другие результаты, сообщите мне. Будет крайне интересно.
http://sqlperformance.com/2016/04/sql-server-2016/string-split-follow-up-1
Спасибо! Стоит еще поковырять тщательнее.
Случайно наткнулся на стать, признаться, глаза закровоточили от “решения в лоб”
StringToWords
(
@String varchar(MAX)
, @Separator varchar(20)
)
RETURNS TABLE
AS
RETURN
(
WITH A AS
(
SELECT
Word = LEFT(
@String
, CASE
WHEN CHARINDEX (@Separator, @String) > 0 THEN CHARINDEX (@Separator, @String) – 1
ELSE DATALENGTH(@String)
END
)
, StartPos = CHARINDEX (@Separator, @String) + DATALENGTH(@Separator)
, EndPos = CHARINDEX (@Separator, @String, CHARINDEX (@Separator, @String) + DATALENGTH(@Separator) )
, Str = @String
, Chk = CAST(1 AS bigint)
, SepLen = DATALENGTH(@Separator)
, RN = 1
, CharFlag = CHARINDEX (@Separator, @String)
UNION ALL
SELECT
Word = SUBSTRING(
@String, A.StartPos, CASE
WHEN A.EndPos – A.StartPos >= 0 THEN A.EndPos – A.StartPos
ELSE DATALENGTH(@String)
END
)
, StartPos = A.EndPos + DATALENGTH(@Separator)
, EndPos = CHARINDEX (@Separator, @String, A.EndPos + DATALENGTH(@Separator) )
, Str = @String
, Chk = CAST(
CASE
WHEN A.EndPos – A.StartPos >= 0 THEN A.EndPos – A.StartPos
ELSE DATALENGTH(@String)
END AS bigint
)
, SepLen = DATALENGTH(@Separator)
, RN = RN + 1
, CharFlag = A.CharFlag
FROM
A
WHERE
A.CharFlag > 0
AND A.Chk DATALENGTH(@String)
)
SELECT Word = LTRIM(RTRIM(Word)), RN FROM A
)
GO
Pingback: SQL Server 2016: Database Scoped Configuration | Олонцев Сергей
>>По умолчанию инсталлятор руководствуется следующей формулой: минимум из 2х значений, количество ядер на вашей системе и 8.
Ядер физических или виртуальных?
Логических, тех, которые видит операционная система.
Еще вопрос
>>Создавать файлов больше, чем у вас ядер в системе, не будет иметь
практического смыла, ввиду того, что одновременно с tempdb не будет
работать больше сессий, чем у вас ядер в системе.
Каждое ядро работает со своим файлом? Или как повезет?
А это не так важно на самом деле. Важно лишь то, есть ли у вас задержки при работе с tempdb в виде latch’ей или задержек по IO. Если есть, надо разбираться, почему они возникают.
>>А это не так важно на самом деле
То есть если есть 64 ядерный сервер, соответственно 64 сессии и все они пишут в один файл tempdb, хотя я их создам ххх.
>>надо разбираться, почему они возникают.
мне кажется в этом случае совсем понятно ПОЧЕМУ
А если они будут писать каждая сессия в свой файл – то будет же лучше.
Вот мне интересно как работает этот механизм
Во-первых, будет зависеть, сколько всего активных сессий на сервере, и сколько из них пишут в tempdb. На то, как их SQL Server раскидает, вы повлиять все равно не сможете. А вот файлов стоит добавлять до тех пор, пока contention не исчезнет. Слишком много их тоже создавать не имеет особого смысла.
Можно для copy-paste программистов скрипт для переноса джобов?
Главное достоинство JSON оценят веб-разработчики, так как XML проигрывает тут по всем статьям.
Back-End серверу(например на C#) не потребуется делать преобразование из XML в JSON. Много мелких request от клиента, с постоянным парсингом на back-end и вы получите провал по производительности. Провал XML станет заметным, когда на ваш сервер в 1секунду производится более 1000 обращений от 1000 разных клиентов одновременно.
Напротив, формат JSON из MS SQL 2016 позволяет напрямую передать его сразу во front-end, без каких-либо нагрузок на back-end.
Приятно, что JSON в поле nvarchar(max) можно хранить до 2Гигабайт.
Не думаю, что какому-то прийдет в голову тащить на веб-клиент, более 2Гиг JSON структуры. И главное сжатие JSON, намного будет быстрее чем использование его собрата BJSON.
Результаты опубликованного теста быстродействия на моем ноуте с 8 гигами и полностью отключенном свопе:
100 000 итераций:
data_type test_id path_expression returned_type elapsed_time_ms
json 1 $[0].age int 9833
json 2 $[2].”first name” varchar 10540
json 3 $[2].skills[0] varchar 11597
json u 1 $[0].age int 11943
json u 2 $[2].”first name” varchar 13137
json u 3 $[2].skills[0] varchar 14387
xml 1 (/root/rec/age)[1] int 15710
xml 2 (/root/rec/@first_name)[3] varchar 16766
xml 3 /root[1]/rec[3]/skills[1]/skill[1] varchar 19090
10 000 итераций:
data_type test_id path_expression returned_type elapsed_time_ms
json 1 $[0].age int 1787
json 2 $[2].”first name” varchar 1003
json 3 $[2].skills[0] varchar 1037
json u 1 $[0].age int 970
json u 2 $[2].”first name” varchar 963
json u 3 $[2].skills[0] varchar 1057
xml 1 (/root/rec/age)[1] int 1050
xml 2 (/root/rec/@first_name)[3] varchar 1040
xml 3 /root[1]/rec[3]/skills[1]/skill[1] varchar 1180
Миллион итераций почему-то не выдерживал SSMS, а не сервер.
https://uploads.disquscdn.com/images/04f386444c672acf97d08d906ce7a85059b2584c76397a7aa915c1f6af199980.jpg У меня получилось совсем другое-результат подкрепляю скриншотом
Т е по Вашим тестам на моем сервере получилось, что XML более шустрый причем существенно, чем JSON
Начиная с 2012 появилась опция for xml …, BINARY BASE64
Т.е. вот такие конструкции – [почти] эквивалентны:
Select Cast(N’plain_text’ as varbinary(max))
for xml path(”), BINARY BASE64
— Конвертируем значение переменной
declare @value varbinary(max);
set @value = cast(N’plain_text’ as varbinary(max));
select cast(N” as xml).value(‘xs:base64Binary(sql:variable(“@value”))’, ‘varchar(max)’) as [encoded_value];
Привет. Не смог найти упоминаний об ограничении в 128 ГБ в других источниках. Возможно оно легаси или относится к редакции стандарт. Но я смог успешно добавить BPE файл 512 GB на сервере с 192 GB RAM 2014 Enterprise.
“Максимальный поддерживаемый размер оперативной памяти 128 Гб, т.е. обладатели систем с большим размером памяти воспользоваться опцией не смогут. И это довольно неприятный момент, т.к. такой и больший объемы вполне доступны покупателям даже для серверов начального уровня.”
Pingback: Как измерить эксплуатационную надежность Big Data и зачем это нужно | Курсы Big Data, Hadoop, Kafka и Машинное обучение