Архитектура доступа к бд
От: BlackEric http://black-eric.lj.ru
Дата: 17.04.19 13:42
Оценка:
Есть старое веб формс приложение, работающее с ms sql. В нем запросы для доступа к бд хранятся в классах в виде строк и в них же при необходимости формируются.
Теперь нужно добавить работу с postgre sql.
Я понимаю, что это классический случай применения Entity Framework, но в данном случае это будет означать с нуля переписать всю работу с бд. А работу с ms sql трогать нельзя и нужно продолжать развивать.
Пока не придумали ничего лучше чем писать:
if (mssql)
{
    return mssqlQuery;
}
else
{
    return postgresQuery;
}


Какие еще есть варианты?
https://github.com/BlackEric001
Re: Архитектура доступа к бд
От: · Великобритания  
Дата: 17.04.19 13:50
Оценка: +2
Здравствуйте, BlackEric, Вы писали:

BE>Какие еще есть варианты?

DAO же, классика.

interface UserDao{
  User GetSomeUser();
}

class MssqlUserDao : UserDao {
  User GetSomeUser()
  {
     return new User ...(mssql.query("SELECT TOP 1..."));
  }
}
class PsqlUserDao : UserDao {
  User GetSomeUser()
  {
     return new User ...(psql.query("SELECT... LIMIT 1"));
  }
}


Притом рефакторинг вполне очевидный — вначале выделить слой Dao с единственной имплементацией Mssql, потом потихоньку начать создавать Psql и заменять реализацию.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: Архитектура доступа к бд
От: BlackEric http://black-eric.lj.ru
Дата: 17.04.19 14:06
Оценка:
Здравствуйте, ·, Вы писали:

·>DAO же, классика.


·>Притом рефакторинг вполне очевидный — вначале выделить слой Dao с единственной имплементацией Mssql, потом потихоньку начать создавать Psql и заменять реализацию.


Да, DAO выделяться будет.
Я вот думаю может работу с PostgreSql писать на linq2db, а потом все заменить на нее, потому что если потом захотят 3 базу поддерживать то это будет закопаться.
https://github.com/BlackEric001
Re[3]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 14:50
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, ·, Вы писали:


BE>·>DAO же, классика.


BE>·>Притом рефакторинг вполне очевидный — вначале выделить слой Dao с единственной имплементацией Mssql, потом потихоньку начать создавать Psql и заменять реализацию.


BE>Да, DAO выделяться будет.

BE>Я вот думаю может работу с PostgreSql писать на linq2db, а потом все заменить на нее, потому что если потом захотят 3 базу поддерживать то это будет закопаться.

Пару таких строк можешь показать? Хотя я давно не встречал запрос который не мог написать на linq2db.
Re[4]: Архитектура доступа к бд
От: BlackEric http://black-eric.lj.ru
Дата: 17.04.19 15:04
Оценка:
Здравствуйте, Danchik, Вы писали:


D>Пару таких строк можешь показать? Хотя я давно не встречал запрос который не мог написать на linq2db.


Там их сотни. ОТ простых до очень сложных агрегирующих выборок.
https://github.com/BlackEric001
Re[3]: Архитектура доступа к бд
От: · Великобритания  
Дата: 17.04.19 15:16
Оценка: +1
Здравствуйте, BlackEric, Вы писали:

BE>·>DAO же, классика.

BE>·>Притом рефакторинг вполне очевидный — вначале выделить слой Dao с единственной имплементацией Mssql, потом потихоньку начать создавать Psql и заменять реализацию.
BE>Да, DAO выделяться будет.
BE>Я вот думаю может работу с PostgreSql писать на linq2db, а потом все заменить на нее, потому что если потом захотят 3 базу поддерживать то это будет закопаться.
Ну пиши Linq2DbUserDao вместо PsqlUserDao Или хоть все сразу. Или можно даже некоторые вызовы из PsqlUserDao делегировать в Linq2DbUserDao и т.п.
Суть лишь в том, что вместо if-else — ООП.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 15:25
Оценка: 8 (2)
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, Danchik, Вы писали:



D>>Пару таких строк можешь показать? Хотя я давно не встречал запрос который не мог написать на linq2db.


BE>Там их сотни. ОТ простых до очень сложных агрегирующих выборок.


Берешь Linqer ну и причесываешь в конце.
А сложные аггригирующие выборки — это то на что linq2db заточен.
Re: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 15:40
Оценка: 1 (1)
BE>Какие еще есть варианты?

https://docs.microsoft.com/ru-ru/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Только EntityFramework не обязательно можно обычные запросы.


public class FooDto
{
    public  Id {get;}
    public  A {get;set;}
    public  B {get;set;}
}


public interface IFooRepository
{
     IEnumerable<FooDto>  GetItems( params );
     void UpdateItem(FooDto item);     
}

public MsSqlRepository : IFooRepository
{
    //... специфика работы с MsSql
}

public PostgresRepository : IFooRepository
{
    //... специфика работы с Postgres
}



везде в коде используешь IFooRepository где нужно работать с Foo.
IFooRepository получаешь через Dependency Injection или если не хочется то крайний вариант
public static Dependencies
{

    // делаешь любым удобным способом переключение с MsSql реализации на Postgres
    public static IFooRepository FooRepository =>  new MsSqlRepository(connectionString);
                                                   //new PostgresRepository(connectionString);
}

// далее работаешь с FooRepository через интерфейс
Dependencies.FooRepository.GetItems();
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 15:42 okon . Предыдущая версия .
Re[2]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 15:53
Оценка: +1 -1
Здравствуйте, okon, Вы писали:


BE>>Какие еще есть варианты?


O>https://docs.microsoft.com/ru-ru/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

O>Только EntityFramework не обязательно можно обычные запросы.

[Skip]

А вот патерн репозиторий я никому не рекомендую. Лишняя абстракция над базой. У вас уже есть EF — абстракция над базой.
Сидишь клепаешь Generic Repository потом Non-Generic Repostory. Потом пробуешь скрестить данные из двух репозиториев — и тут получается офигенно замоканный тормознутый солюшин.

Да в принципе уже разжевывали
http://rsdn.org/forum/dotnet/6872836.flat#6872836
Автор: Spinifex
Дата: 14.08.17
Re[3]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 16:03
Оценка:
D>А вот патерн репозиторий я никому не рекомендую. Лишняя абстракция над базой. У вас уже есть EF — абстракция над базой.

Не совсем, если достаточно EF, то да, можно не делать.
Но во всех остальных случаях либо EF не достаточно или для данной СУБД не реализован,
например для Oracle запросы приходится писать в ручную, т.к. то что генерит EF нормально работать может только на простых или маленьких базах.

На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[4]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 16:08
Оценка:
Здравствуйте, okon, Вы писали:

D>>А вот патерн репозиторий я никому не рекомендую. Лишняя абстракция над базой. У вас уже есть EF — абстракция над базой.


O>Не совсем, если достаточно EF, то да, можно не делать.

O>Но во всех остальных случаях либо EF не достаточно или для данной СУБД не реализован,
O>например для Oracle запросы приходится писать в ручную, т.к. то что генерит EF нормально работать может только на простых или маленьких базах.

O>На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.


Ну вот представь себе что я уже пару лет не писал запросы в коде вручную. Все прекрастно генерит linq2db.
То что EF к ним плохо заточен — это спасибо его дизайну и молодости EF Core. Про EF 6 я вообще молчу, да это ужас.
Re[5]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 16:17
Оценка:
O>>На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.

D>Ну вот представь себе что я уже пару лет не писал запросы в коде вручную. Все прекрастно генерит linq2db.

D>То что EF к ним плохо заточен — это спасибо его дизайну и молодости EF Core. Про EF 6 я вообще молчу, да это ужас.

А какая СУБД ? Размеры таблиц ?

Тут важно что плохо заточен, не так важно почему именно,
поэтому любое более менее сложное и высоконагруженное решение потребует ухода от EF.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[6]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 16:24
Оценка:
Здравствуйте, okon, Вы писали:

O>>>На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.


D>>Ну вот представь себе что я уже пару лет не писал запросы в коде вручную. Все прекрастно генерит linq2db.

D>>То что EF к ним плохо заточен — это спасибо его дизайну и молодости EF Core. Про EF 6 я вообще молчу, да это ужас.

O>А какая СУБД ? Размеры таблиц ?


Любая из 10+ поддерживаемых (уже и сам не помню сколько их)
Размеры таблиц тут как бы не релевантны. Генерится оптимальный сиквел, а уж как ты индексы настроил — сам себе буратино.

O>Тут важно что плохо заточен, не так важно почему именно,

O>поэтому любое более менее сложное и высоконагруженное решение потребует ухода от EF.

Так давно и ушел, когда понял что вся прелесть linq была уничтожена горе решениями.
Re[7]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 16:41
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, okon, Вы писали:


O>>>>На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.


D>>>Ну вот представь себе что я уже пару лет не писал запросы в коде вручную. Все прекрастно генерит linq2db.

D>>>То что EF к ним плохо заточен — это спасибо его дизайну и молодости EF Core. Про EF 6 я вообще молчу, да это ужас.

O>>А какая СУБД ? Размеры таблиц ?


D>Любая из 10+ поддерживаемых (уже и сам не помню сколько их)

D>Размеры таблиц тут как бы не релевантны. Генерится оптимальный сиквел, а уж как ты индексы настроил — сам себе буратино.
Релевантны, потому что таблицы с 10 000 записей работать будут нормально как правило и без индексов.
В более менее промышленых решениях которые я встречал там от 100+ таблиц
Также от 1+ млн записей, в памяти таблицы не помещаются, индексы по всем вариантам фильтров не построишь.

p.s. да кстати мы говорим сейчас об архитектуре, так вот что касается всякий внешних библиотек,
типа linq2db и др, в хорошей архитектуре есть рекомендации делать прослойку типа ILinqToDB для того чтобы можно было
легче в будущем избавиться от конкретной библиотеки и использовать другую, особенно когда спецификой этой библиотеки начинает обрастать решение.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 16:46 okon . Предыдущая версия .
Re[8]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 16:50
Оценка:
Здравствуйте, okon, Вы писали:

[skip]

D>>Любая из 10+ поддерживаемых (уже и сам не помню сколько их)

D>>Размеры таблиц тут как бы не релевантны. Генерится оптимальный сиквел, а уж как ты индексы настроил — сам себе буратино.
O>Релевантны, потому что таблицы с 10 000 записей работать будут нормально как правило и без индексов.
O>В более менее промышленых решениях которые я встречал там от 100+ таблиц
O>Также от 1+ млн записей, в памяти таблицы не помещаются, индексы по всем вариантам фильтров не построишь.

Извините, мы не дизайн базы обговариваем, а способ доступа к ним. Среди пользователей linq2db есть и такие кто говорит об 1000+ таблиц и никто еще на скорость не жаловался.

Какой же умник будет миллионы записей на клиент тянуть? Зачем?

Балк удаления, апдейты и вставки присутствуют, работа со времерными таблицами есть, оконные функции присутствуют, CTE из каробки, самый быстрый маппер на рынке. Мне достаточно.
Re[9]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 17:08
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, okon, Вы писали:


D>[skip]


D>>>Любая из 10+ поддерживаемых (уже и сам не помню сколько их)

D>>>Размеры таблиц тут как бы не релевантны. Генерится оптимальный сиквел, а уж как ты индексы настроил — сам себе буратино.
O>>Релевантны, потому что таблицы с 10 000 записей работать будут нормально как правило и без индексов.
O>>В более менее промышленых решениях которые я встречал там от 100+ таблиц
O>>Также от 1+ млн записей, в памяти таблицы не помещаются, индексы по всем вариантам фильтров не построишь.

D>Извините, мы не дизайн базы обговариваем, а способ доступа к ним. Среди пользователей linq2db есть и такие кто говорит об 1000+ таблиц и никто еще на скорость не жаловался.

дело не в 1000+ таблицах а количестве записей.
Но в целом 1000+ таблиц реальной базы ( как правило там и данных будет 1млн+ ) если покажете бенчмарки для linq2db как он справляется автогенеренными запросами, было бы интересно.
Если конечно это не для красного словца сказано.

D>Какой же умник будет миллионы записей на клиент тянуть? Зачем?

Так никто обычно и не тянет миллионы на клиент, но в базе чтобы отфильтровать нужные данные вам придется по этим миллионам пройтись как-то.
При это СУБД всю таблицу к себе в память поместить не может, а также нет возможности по всем кейсами индексы сделать их просто будет миллионы и будет тормозить вставку данных.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 17:12 okon . Предыдущая версия .
Re[10]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 17:15
Оценка:
Здравствуйте, okon, Вы писали:

[skip]

D>>Извините, мы не дизайн базы обговариваем, а способ доступа к ним. Среди пользователей linq2db есть и такие кто говорит об 1000+ таблиц и никто еще на скорость не жаловался.

O>дело не в 1000+ таблицах а количестве записей.
O>Но в целом 1000+ таблиц если покажете бенчмарки для linq2db как он справляется автогенеренными запросами, было бы интересно.
O>Если конечно это не для красного словца сказано.

Там говорилось о чем-то страшном, сори концы искать нету времени.

D>>Какой же умник будет миллионы записей на клиент тянуть? Зачем?

O>Так никто обычно и не тянет миллионы на клиент, но в базе чтобы отфильтровать нужные данные вам придется по этим миллионам пройтись как-то.
O>При это СУБД всю таблицу к себе в память поместить не может, а также нет возможности по всем кейсами индексы сделать их просто будет миллионы и будет тормозить вставку данных.

Опять же мы не дизайн базы обговариваем. Если ощутимый прогиб в скоросоти — анализируйте план.
Вы же сиквелы ручками пишете, так вот на linq2db их можно писать точно так же один в один, но имея типобезопасный linq и query decomposition по умолчанию, просто используйте IQueryable.
Re[11]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 17:32
Оценка: -1
D>Опять же мы не дизайн базы обговариваем. Если ощутимый прогиб в скоросоти — анализируйте план.
D>Вы же сиквелы ручками пишете, так вот на linq2db их можно писать точно так же один в один, но имея типобезопасный linq и query decomposition по умолчанию, просто используйте IQueryable.
А как там оракловые хинты к запросу указать ?

Вот например
https://docs.oracle.com/cd/B12037_01/server.101/b10752/hintsref.htm

SELECT /*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
           USE_MERGE(j) FULL(j) */
    e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_sal
  FROM employees e1, employees e2, job_history j
  WHERE e1.employee_id = e2.manager_id
    AND e1.employee_id = j.employee_id
    AND e1.hire_date = j.start_date
  GROUP BY e1.first_name, e1.last_name, j.job_id
  ORDER BY total_sal;


Как этот запрос описать на linq2db
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[12]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 18:17
Оценка:
Здравствуйте, okon, Вы писали:

D>>Опять же мы не дизайн базы обговариваем. Если ощутимый прогиб в скоросоти — анализируйте план.

D>>Вы же сиквелы ручками пишете, так вот на linq2db их можно писать точно так же один в один, но имея типобезопасный linq и query decomposition по умолчанию, просто используйте IQueryable.
O>А как там оракловые хинты к запросу указать ?

O>Вот например

O>https://docs.oracle.com/cd/B12037_01/server.101/b10752/hintsref.htm

O>
O>SELECT /*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
O>           USE_MERGE(j) FULL(j) */
O>    e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_sal
O>  FROM employees e1, employees e2, job_history j
O>  WHERE e1.employee_id = e2.manager_id
O>    AND e1.employee_id = j.employee_id
O>    AND e1.hire_date = j.start_date
O>  GROUP BY e1.first_name, e1.last_name, j.job_id
O>  ORDER BY total_sal;
O>


O>Как этот запрос описать на linq2db


Ну что же, попал. Для SQL Serevr мы это поддержали, часик и такой вариант без проблем для оракла. Необходимости небыло.

Что-то типа (можно и поприятней подход придумать):
using (var db = new DataConnection())
{
   db.StatementHints.Add(@"/*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
           USE_MERGE(j) FULL(j) */");

   var query = from e1 in db.GetTable<Employee>()
               from e2 in db.GetTable<Employee>().InnerJoin(e2 => e2.ManagerId == e1.EmployeeId)
               from j  in db.GetTable<JobHitory>().InnerJoin(j => j.EmployeeId == e1.EmployeeId && j.StartDate == e1.HireDate)
               group new {e1, e2} by new { e1.FirstName, e1.LastName, j.JobId } into g
               select new 
               {
                  g.Key.FirstName,    
                  g.Key.LastName,    
                  g.Key.JobId,
                  TotalSal = g.Sum(e => e.e2.Salary)
               };
    query = query.OrderBy(e => e. TotalSal);
    var result = query.ToList();
}
Re[13]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 18:39
Оценка:
D>Что-то типа (можно и поприятней подход придумать):
D>
D>using (var db = new DataConnection())
D>{
D>   db.StatementHints.Add(@"/*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
D>           USE_MERGE(j) FULL(j) */");
D>}
D>


Но в этом случае ты как раз теряешь то с чего начиналась тема , что эта прослойка заменяет абстракцию IRepository.
Тут ты указал специфику Оракла и этот же код нельзя будет также использовать на MSSQL.
Т.е. потребуется как минимум 2 реализации : с хинтами для оракла, с хинтами для mssql, а в реальной жизни скорее всего не только хинты но и сами запросы немного будут разные для разных СУБД
если придется оптимизировать.


Второй момент — особенности специфичные функции Oracle, например использование Sequence, как написать например
select schema.sequence.NEXTVAL from dual;
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 18:40 okon . Предыдущая версия . Еще …
Отредактировано 17.04.2019 18:39 okon . Предыдущая версия .
Re[14]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 18:58
Оценка:
Здравствуйте, okon, Вы писали:


D>>Что-то типа (можно и поприятней подход придумать):

D>>
D>>using (var db = new DataConnection())
D>>{
D>>   db.StatementHints.Add(@"/*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
D>>           USE_MERGE(j) FULL(j) */");
D>>}
D>>


O>Но в этом случае ты как раз теряешь то с чего начиналась тема , что эта прослойка заменяет абстракцию IRepository.

O>Тут ты указал специфику Оракла и этот же код нельзя будет также использовать на MSSQL.
O>Т.е. потребуется как минимум 2 реализации : с хинтами для оракла, с хинтами для mssql, а в реальной жизни скорее всего не только хинты но и сами запросы немного будут разные для разных СУБД
O>если придется оптимизировать.

Во первых, так играться с хинтами мне практически никогда не надо было. Во вторых коня на переправе меняют раз в никогда.

O>Второй момент — особенности специфичные функции Oracle, например использование Sequence, как написать например

O>
O>select schema.sequence.NEXTVAL from dual;
O>


Очень даже просто:

static class Oracle
{
   [SqlExtension("{0}.{1}.NEXTVAL", ServerSideOnly = true)]
   public static long NextVal(string schema, string sequence)
   {
      throw new NotImplementedException();
   }
}


var nextValue = db.Select(() => Oracle.NextVal("schema", "sequence"));


Используй потом аж завались
Re[15]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 19:14
Оценка:
D>Во первых, так играться с хинтами мне практически никогда не надо было. Во вторых коня на переправе меняют раз в никогда.

Не только хинты, те же Sequence.Nextval и другая тьма специфичных ораклу операторов используется достаточно часто.
Топик был как раз про случай появления двух коней как лучше поддержать.
Если заранее известно что коня второго не будет то можно пилить один провайдер как угодно.

D>Очень даже просто:

D>var nextValue = db.Select(() => Oracle.NextVal("schema", "sequence"));
D>[/cs]
D>Используй потом аж завались

Но это был пример не про то что сложно экстеншен сделать,
а про то что эту логика будет специфична и ее нельзя повторно использовать для разных СУБД.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[16]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 19:25
Оценка:
Здравствуйте, okon, Вы писали:


D>>Во первых, так играться с хинтами мне практически никогда не надо было. Во вторых коня на переправе меняют раз в никогда.


O>Не только хинты, те же Sequence.Nextval и другая тьма специфичных ораклу операторов используется достаточно часто.

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

D>>Очень даже просто:

D>>var nextValue = db.Select(() => Oracle.NextVal("schema", "sequence"));
D>>[/cs]
D>>Используй потом аж завались

O>Но это был пример не про то что сложно экстеншен сделать,

O>а про то что эту логика будет специфична и ее нельзя повторно использовать для разных СУБД.

Ну и у меня сложилось впечатление что я борюсь с КО

Стандартные вещи работают на всех базах данных со всевозможной эмуляцией. Но если тут такой изврат, то вперед писать экстеншины.
EF вам такой глубокой кастомизации никогда не даст.
Все можно вынести в виртуальные функции, да и и экстеншины можно привязать к определенной базе и очень даже гибко.
Re[17]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 19:38
Оценка: -1
D>Стандартные вещи работают на всех базах данных со всевозможной эмуляцией. Но если тут такой изврат, то вперед писать экстеншины.
Стандартные вещи хороши, но все зависит от задач.
Если вы пишете какую-нибудь для себя базу данных телефонов или бухгалтерию для небольшого ип то там да EF/l2db достаточно будет.

Если преполагается внедрение в более чем одной организации, там точно будут разные базы где-то MSSQL, где-то Oracle.
Если преполагается нагрузка, то добавятся задачи по оптимизации и там уже на разных СУБД разные конструкции надо применять для оптимальной работы,
хинты, структура запроса будут разные, применение специфичных функций.

D>EF вам такой глубокой кастомизации никогда не даст.

D>Все можно вынести в виртуальные функции, да и и экстеншины можно привязать к определенной базе и очень даже гибко.

Можно конечно делать общий репозиторий и от него наследовать кастомные, но это не отменяет cам паттерн IRepository и его использование.
С запросами не получится совсем гибко, например в Oracle чтобы вставить новую запись вы сделаете сначала Sequence.NextVal, в MSSQL есть автоинкремент.
Некоторые операции для обеспечения гибкости придется эмулировать на СУБД, т.к. иначе вам придется данные обрабатывать в логике на клиенте, а это значит вытягивать их из СУБД.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[18]: Архитектура доступа к бд
От: vorona  
Дата: 17.04.19 20:25
Оценка:
Здравствуйте, okon, Вы писали:

NEXT VALUE FOR (Transact-SQL)
Re[19]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 20:43
Оценка:
Здравствуйте, vorona, Вы писали:

V>Здравствуйте, okon, Вы писали:


V>NEXT VALUE FOR (Transact-SQL)


Да получается Sequence добавили уже давно и его можно повторить, но не в этом суть.
Суть в том что все равно остается достаточно часто употребляемые специфичные функции которые не дублируются , например дублируется ли CONNECT BY LEVEL ?
и для оптимизации потребуется немного разная структура запросов, т.к. планировщики запросов также немного отличаются
SELECT *
FROM (    SELECT LEVEL n, TO_DATE ('31/12/2010', 'DD/MM/YYYY') + NUMTODSINTERVAL (LEVEL, 'day') CurrDate
          FROM DUAL
    CONNECT BY LEVEL <= 2000)
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[20]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 21:23
Оценка: +1
Здравствуйте, okon, Вы писали:

O>Здравствуйте, vorona, Вы писали:


V>>Здравствуйте, okon, Вы писали:


V>>NEXT VALUE FOR (Transact-SQL)


O>Да получается Sequence добавили уже давно и его можно повторить, но не в этом суть.

O>Суть в том что все равно остается достаточно часто употребляемые специфичные функции которые не дублируются , например дублируется ли CONNECT BY LEVEL ?
O>и для оптимизации потребуется немного разная структура запросов, т.к. планировщики запросов также немного отличаются
O>
O>SELECT *
O>FROM (    SELECT LEVEL n, TO_DATE ('31/12/2010', 'DD/MM/YYYY') + NUMTODSINTERVAL (LEVEL, 'day') CurrDate
O>          FROM DUAL
O>    CONNECT BY LEVEL <= 2000)
O>


Человек, еще раз, на переправе никто коня не меняет. Сделаете предварительную абстракцию — вам же хуже, точнее перформансу. Пишите оптимально, потом ищите точки соприкосновения.
Re[14]: Архитектура доступа к бд
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.04.19 09:38
Оценка: +1
Здравствуйте, okon, Вы писали:

O>Но в этом случае ты как раз теряешь то с чего начиналась тема , что эта прослойка заменяет абстракцию IRepository.

O>Тут ты указал специфику Оракла и этот же код нельзя будет также использовать на MSSQL.
O>Т.е. потребуется как минимум 2 реализации : с хинтами для оракла, с хинтами для mssql, а в реальной жизни скорее всего не только хинты но и сами запросы немного будут разные для разных СУБД
O>если придется оптимизировать.


O>Второй момент — особенности специфичные функции Oracle, например использование Sequence, как написать например

O>
O>select schema.sequence.NEXTVAL from dual;
O>

Нужно просто понять, что "абстракция IRepository" — это недостижимая утопия. Как вы будете переносить вот этот sequence.NEXTVAL в базу, в которой вообще сиквенсов нету?
У вас два варианта:
1. Изобрести кособрюхую эмуляцию, например create table sequence (id int identity not null), и потом кажный раз делать insert into sequence default values; select @@scope_identity
2. Перепахать всю схему решения на использование identity-колонок вместо последовательностей/генераторов

Первый — проблемы с производительностью, второй — уход от идиллии "щаз заменим IRepository и взлетим".

Чего вы хотите? Если вы хотите (зачем-то) универсальности в плане движка СУБД, и готовы наплевать на производительность — то link2db даст вам возможность быстро писать универсальный код, не отвлекаясь на бойлерплейт репозиториев.

Если вы хотите выжимать максимум производительности, то link2db даст вам возможность быстро писать специфичный для СУБД код, не отвлекаясь на бойлерплейт репозиториев.

Более того, при будущей миграции на другую СУБД вы всегда сможете инкапсулировать код. Сделаете класс QueryExtensions с extension методом:

public static IQueryable<EmpSalary> GetEmployeesSalary(this DataConnection db)
{
   var query = from e1 in db.GetTable<Employee>()
               from e2 in db.GetTable<Employee>().InnerJoin(e2 => e2.ManagerId == e1.EmployeeId)
               from j  in db.GetTable<JobHitory>().InnerJoin(j => j.EmployeeId == e1.EmployeeId && j.StartDate == e1.HireDate)
               group new {e1, e2} by new { e1.FirstName, e1.LastName, j.JobId } into g
               select new EmpSalary
               {
                  FirstName =g.Key.FirstName,    
                  LastName = g.Key.LastName,    
                  JobId = g.Key.JobId,
                  TotalSal = TotalSal = g.Sum(e => e.e2.Salary)
               };
    return query.OrderBy(e => e. TotalSal);
}

Сделаете OracleDataConnection, отнаследованный от DataConnection.
В нём напишете вот так:
public IEnumerable<EmpSalary> GetEmployeesSalary()
{
   StatementHints.Add(@"/*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) USE_MERGE(j) FULL(j) */");
   var query = QueryExtensions.GetEmployeesSalary(this); 
   return query.ToList(); // force hints application to avoid reusing the query in other statements
}

Всё. При переходе на MS SQL хинты оракла исчезнут, останется только нормальный код, умеющий полагаться на разумность встроенного оптимизатора СУБД.
Если когда-то понадобится подтюнить этот конкретный запрос для MS SQL — сделаете точно так же, только укажете соответствующие хинты в MssqlDataConnection.GetEmployeesSalary().
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Архитектура доступа к бд
От: Sharov Россия  
Дата: 18.04.19 09:44
Оценка:
Здравствуйте, okon, Вы писали:


D>>Что-то типа (можно и поприятней подход придумать):

D>>
D>>using (var db = new DataConnection())
D>>{
D>>   db.StatementHints.Add(@"/*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
D>>           USE_MERGE(j) FULL(j) */");
D>>}
D>>


O>Но в этом случае ты как раз теряешь то с чего начиналась тема , что эта прослойка заменяет абстракцию IRepository.

O>Тут ты указал специфику Оракла и этот же код нельзя будет также использовать на MSSQL.
O>Т.е. потребуется как минимум 2 реализации : с хинтами для оракла, с хинтами для mssql, а в реальной жизни скорее всего не только хинты но и сами запросы немного будут разные для разных СУБД
O>если придется оптимизировать.

Выше уже описали ООП подход для решения ентой проблемы. Т.е. создать дополнительный метод StatementHints, который для каждой базы будет свой. А затем идет общий запрос на linq(2db).
Кодом людям нужно помогать!
Re[15]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 09:56
Оценка:
S>Нужно просто понять, что "абстракция IRepository" — это недостижимая утопия. Как вы будете переносить вот этот sequence.NEXTVAL в базу, в которой вообще сиквенсов нету?


S>У вас два варианта:

S>1. Изобрести кособрюхую эмуляцию, например create table sequence (id int identity not null), и потом кажный раз делать insert into sequence default values; select @@scope_identity
S>2. Перепахать всю схему решения на использование identity-колонок вместо последовательностей/генераторов

а чем поможет в данном случае linq2db ? точно также.

в IRepository будет функция например long GetNewId() как ее реализовать в конкретной базе — дело базы.
Если база не поддерживает Sequence, то linq2db тут как вас спасет ? Вам все равно что-то придется написать если логика программы требует GetNewId() из базы.



S>Чего вы хотите? Если вы хотите (зачем-то) универсальности в плане движка СУБД, и готовы наплевать на производительность — то link2db даст вам возможность быстро писать универсальный код, не отвлекаясь на бойлерплейт репозиториев.


Универсальность движка СУБД требуется если вы пишете софт на продажу , а не под конкретную контору.
link2db как мы выяснили в ряде промышленных случаях которые потребуют оптимизации не даст универсальности и универсального кода.

Если только использовать самые простые конструкции.
Напомню — CONNECT BY LEVEL как раз позволит быстро написать код, который делает иерархический запрос, но это будет не универсано.


S>Если вы хотите выжимать максимум производительности, то link2db даст вам возможность быстро писать специфичный для СУБД код, не отвлекаясь на бойлерплейт репозиториев.


Тут противоречие как только у нас появляется специфичный код, так сразу рисуется репозиторий.
Либо не должно быть специфики тогда можно обойтись "упрощенкой" в виде linq2db.


S>Более того, при будущей миграции на другую СУБД вы всегда сможете инкапсулировать код. Сделаете класс QueryExtensions с extension методом:

S>Всё. При переходе на MS SQL хинты оракла исчезнут, останется только нормальный код, умеющий полагаться на разумность встроенного оптимизатора СУБД.

Может быть верно в частном случае, но во первых хинты не только в первом select может быть а во всех вложенных, во вторых разные субд требуют немного по разному реализовывать запросы которые бы работали оптимально.
Условно где-то лучше написать select * from а where a.id in ( select * from b ) , а где-то with b select a in b, это так "псевдо sql" думаю понятно о чем речь.
Поэтому одинакового кода добиться сложно если придется оптимизировать каждую субд.

Приведу аналогию — представим что у нас есть оригинальное предожение на английском, и мы для локализации под разные языки.

1) можем перевести через автопереводчик
2) можем перевести с помощью нейтива и для каждого языка сделать свое предложение.

Понятно что 1й случай в каких то ситуациях проще и выгоднее, но в общем случае страдает качество и не применимо.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[15]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 09:59
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, okon, Вы писали:



D>>>Что-то типа (можно и поприятней подход придумать):

D>>>
D>>>using (var db = new DataConnection())
D>>>{
D>>>   db.StatementHints.Add(@"/*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
D>>>           USE_MERGE(j) FULL(j) */");
D>>>}
D>>>


O>>Но в этом случае ты как раз теряешь то с чего начиналась тема , что эта прослойка заменяет абстракцию IRepository.

O>>Тут ты указал специфику Оракла и этот же код нельзя будет также использовать на MSSQL.
O>>Т.е. потребуется как минимум 2 реализации : с хинтами для оракла, с хинтами для mssql, а в реальной жизни скорее всего не только хинты но и сами запросы немного будут разные для разных СУБД
O>>если придется оптимизировать.

S>Выше уже описали ООП подход для решения ентой проблемы. Т.е. создать дополнительный метод StatementHints, который для каждой базы будет свой. А затем идет общий запрос на linq(2db).


Там дальше будет обсуждение, я просто уже 3й раз буду писать, поэтому буду краток, детали в обсуждении уже есть.
дело не только в хинтах ( которые не только в начале запроса могут быть ), структура запроса, специфичные для субд операторы для запроса в теле.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[16]: Архитектура доступа к бд
От: Sharov Россия  
Дата: 18.04.19 10:13
Оценка:
Здравствуйте, okon, Вы писали:

O>Там дальше будет обсуждение, я просто уже 3й раз буду писать, поэтому буду краток, детали в обсуждении уже есть.

O> дело не только в хинтах ( которые не только в начале запроса могут быть ), структура запроса, специфичные для субд операторы для запроса в теле.

По хорошему, ORM должен давать возможность указывать енти детали для драйвера.
Кодом людям нужно помогать!
Re[17]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 10:17
Оценка:
S>По хорошему, ORM должен давать возможность указывать енти детали для драйвера.
Просто при оптимизации для каждого драйвера будут свои детали, и будет плохо когда нужно что-то подкрутить для Oracle,
а мы в случае linq2db крутим в итоге единый код для всех баз, в итоге классика когда правишь в одном месте, отъезжает в других.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[18]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 18.04.19 10:27
Оценка: +1
Здравствуйте, okon, Вы писали:

S>>По хорошему, ORM должен давать возможность указывать енти детали для драйвера.

O>Просто при оптимизации для каждого драйвера будут свои детали, и будет плохо когда нужно что-то подкрутить для Oracle,
O>а мы в случае linq2db крутим в итоге единый код для всех баз, в итоге классика когда правишь в одном месте, отъезжает в других.

Это высосано из пальца. Ничего не съедет. Съедет когда вы в вашем базовом (гипотетическом) репозитории что-то докрутили.
Прострелить себе ногу вы всегда можете.

Кстати, для чего вам NextValue? Ужне не для вставки ли? Не устроит ли вас просто функция InsertWithIdentity, которая сделана для всех поддерживаемых баз?
Re[19]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 10:41
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, okon, Вы писали:


S>>>По хорошему, ORM должен давать возможность указывать енти детали для драйвера.

O>>Просто при оптимизации для каждого драйвера будут свои детали, и будет плохо когда нужно что-то подкрутить для Oracle,
O>>а мы в случае linq2db крутим в итоге единый код для всех баз, в итоге классика когда правишь в одном месте, отъезжает в других.

D>Это высосано из пальца. Ничего не съедет. Съедет когда вы в вашем базовом (гипотетическом) репозитории что-то докрутили.

Ну в моем случае может и не быть базового, зависит от вашего разумного выбора что и как будет меняться.
А в случае linq2db, получается общий код и любая правка или изменение структуры запроса требует тестирования на всех базах.

D>Прострелить себе ногу вы всегда можете.


D>Кстати, для чего вам NextValue? Ужне не для вставки ли? Не устроит ли вас просто функция InsertWithIdentity, которая сделана для всех поддерживаемых баз?

Часто для получения Id еще до непосредственно вставки, с гарантией что никто его уже не заберет.
Но NextValue это далеко не единственная специфика и общим кодом для всех баз бойтись можно будет только в простых случаях, не требующих оптимизации.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[18]: Архитектура доступа к бд
От: Sharov Россия  
Дата: 18.04.19 10:47
Оценка:
Здравствуйте, okon, Вы писали:

S>>По хорошему, ORM должен давать возможность указывать енти детали для драйвера.

O>Просто при оптимизации для каждого драйвера будут свои детали, и будет плохо когда нужно что-то подкрутить для Oracle,
O>а мы в случае linq2db крутим в итоге единый код для всех баз, в итоге классика когда правишь в одном месте, отъезжает в других.

Для каждой базы будет свой переопределяемый метод, где нужно сообщить специфичные детали.
Кодом людям нужно помогать!
Re[19]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 10:55
Оценка:
S>Для каждой базы будет свой переопределяемый метод, где нужно сообщить специфичные детали.

Ну это уже репозиторий и получится, будет есля правильно понял что имеете ввиду


public interface IRepository
{
  Result Select();
}

public BaseRepository  : IRepository
{
    virtual Result Select();
}

public OracleRepository : BaseRepository
{
    override Result Select();
}

public MsSqlRepository : BaseRepository
{
    override Result Select();
}
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[16]: Архитектура доступа к бд
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.04.19 11:02
Оценка: +1
Здравствуйте, okon, Вы писали:

S>>Нужно просто понять, что "абстракция IRepository" — это недостижимая утопия. Как вы будете переносить вот этот sequence.NEXTVAL в базу, в которой вообще сиквенсов нету?



S>>У вас два варианта:

S>>1. Изобрести кособрюхую эмуляцию, например create table sequence (id int identity not null), и потом кажный раз делать insert into sequence default values; select @@scope_identity
S>>2. Перепахать всю схему решения на использование identity-колонок вместо последовательностей/генераторов

O>а чем поможет в данном случае linq2db ? точно также.


O>в IRepository будет функция например long GetNewId() как ее реализовать в конкретной базе — дело базы.

Это как раз вариант "давайте сделаем плохо, но универсально".
O>Если база не поддерживает Sequence, то linq2db тут как вас спасет ? Вам все равно что-то придется написать если логика программы требует GetNewId() из базы.
Для начала, link2db вас поставит перед принятием решения на стороне базы. Вы будете мыслить не терминами "репозиториев", а терминами сценариев. Например "как мы получаем номер для нового документа"?
Может внезапно оказаться, что в более человеческой СУБД GetNewId вообще не нужен, потому как его использовали для генерации PK, а в потомках Sybase она встроена в определение таблиц.

Это спровоцирует вас провести рефакторинг, и подробности вроде вызовов GetNewId уедут в тот метод, который изготавливает новую entity в базе.

S>>Чего вы хотите? Если вы хотите (зачем-то) универсальности в плане движка СУБД, и готовы наплевать на производительность — то link2db даст вам возможность быстро писать универсальный код, не отвлекаясь на бойлерплейт репозиториев.

O>Универсальность движка СУБД требуется если вы пишете софт на продажу , а не под конкретную контору.
Мы пишем софт на продажу. Универсальность движка СУБД не потребовалась ни разу. Использовано было ровно 1.002 движка — то есть Постгре у всех, кроме двух экспериментов с виндой и MS SQL.
По результатам было принято эпохальное решение "стюардессу закопать", потому что стоимость поддержки этих отщепенцев в разы превышает прибыль от них.
O>link2db как мы выяснили в ряде промышленных случаях которые потребуют оптимизации не даст универсальности и универсального кода.
Link2db вообще не очень претендовал на универсальность. Он претендует на то, чтобы реальным разработчикам писать реальный код. Без компромиссов вроде "пишем быстро, но код говно", и "работает приемлемо, но 80% кода — бойлерплейт".

O>Если только использовать самые простые конструкции.

O>Напомню — CONNECT BY LEVEL как раз позволит быстро написать код, который делает иерархический запрос, но это будет не универсано.
Конечно. Правильный способ — использовать ансишный CTE, который работает более-менее в любой СУБД, выпущенной после 2010.

O>Тут противоречие как только у нас появляется специфичный код, так сразу рисуется репозиторий.

Мы с вами, по-видимому, по-разному понимаем термин "репозиторий".

O>Либо не должно быть специфики тогда можно обойтись "упрощенкой" в виде linq2db.

вообще, link2db достаточно умный, чтобы автоматически порождать адекватные идиомы SQL. Скажем, поддержка иерархических запросов через CTE в нём есть.

В то, что оракл требует хинтов на каждый чих, лично я не верю — не может он быть настолько отстоем.
Это означает, что у реального приложения на 1000 запросов будет два-три десятка таких, которым потребовались хинты. Подход "с репозиторием" будет означать наличие 1000 методов, из которых только 20-30 имеют нетривиальную реализацию.
Болезнь "CRUD-хранимки", вид сбоку. Linq позволит написать 1000 запросов в лоб и взлететь, а потом подтюнить ровно те 20-30, которые того заслуживают.

O>Может быть верно в частном случае, но во первых хинты не только в первом select может быть а во всех вложенных, во вторых разные субд требуют немного по разному реализовывать запросы которые бы работали оптимально.

O>Условно где-то лучше написать select * from а where a.id in ( select * from b ) , а где-то with b select a in b, это так "псевдо sql" думаю понятно о чем речь.
Такие вещи link2db отрабатывает сам, из коробки.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[20]: Архитектура доступа к бд
От: · Великобритания  
Дата: 18.04.19 11:12
Оценка: +1
Здравствуйте, okon, Вы писали:

D>>Это высосано из пальца. Ничего не съедет. Съедет когда вы в вашем базовом (гипотетическом) репозитории что-то докрутили.

O>Ну в моем случае может и не быть базового, зависит от вашего разумного выбора что и как будет меняться.
O>А в случае linq2db, получается общий код и любая правка или изменение структуры запроса требует тестирования на всех базах.
Ты немного в не ту сторону думаешь. Тут ведь как. Есть некое приложение, которое должно работать во всех базах. По сути три подхода
1. иметь свой код на каждую базу
2. иметь общий код на все базы
3. иметь общий код на все базы и возможность кастомизировать под конкретную.

(1) хорош когда у тебя очень много заточки под каждую конкретную базу для вылизывания производительности. Как правило, относительно редкий случай.
(2) хорош когда у тебя много бизнес-кода и проект развивается. И приходится в угоду общности жертвовать производительностью. "Давайте добавим новое поле в Аккаунт" — более типично, чем "ой, у нас оракл притормаживает на данной операции, давайте добавлять хинты и хранимки". Поэтому чаще всего получается "любая правка" будет изменением бизнес-требований, а значит гораздо важнее иметь возможность поменять одно место в коде и потом просто протестировать на всех базах, чем менять код под каждую из баз и потом тоже так же всё тестировать.
А (3) это комбинация (1) и (2) — компромис и часто результат развития варианта (2).
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[17]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 11:41
Оценка:
O>>а чем поможет в данном случае linq2db ? точно также.
O>>в IRepository будет функция например long GetNewId() как ее реализовать в конкретной базе — дело базы.
S>Это как раз вариант "давайте сделаем плохо, но универсально".
Репозиторий — универсально ? Да не, я бы сказал что наоборот, в идеале я бы сделал для каждой субд свой изолированный код.


S>Может внезапно оказаться, что в более человеческой СУБД GetNewId вообще не нужен, потому как его использовали для генерации PK, а в потомках Sybase она встроена в определение таблиц.

S>Это спровоцирует вас провести рефакторинг, и подробности вроде вызовов GetNewId уедут в тот метод, который изготавливает новую entity в базе.

Не суть до чего дойдет мыслительный процесс, важно в итоге родится некий метод DoSomething() который должен использоваться бизнес-логикой и эта логика не должна знать специфику СУБД.
В котором досаточно часто может потребоваться специфичная функция как для оптимальной работы так и для того чтобы вприцнипе работало на данной СУБД.

S>>>Чего вы хотите? Если вы хотите (зачем-то) универсальности в плане движка СУБД, и готовы наплевать на производительность — то link2db даст вам возможность быстро писать универсальный код, не отвлекаясь на бойлерплейт репозиториев.

O>>Универсальность движка СУБД требуется если вы пишете софт на продажу , а не под конкретную контору.
S>Мы пишем софт на продажу. Универсальность движка СУБД не потребовалась ни разу. Использовано было ровно 1.002 движка — то есть Постгре у всех, кроме двух экспериментов с виндой и MS SQL.

Ну повезло, не знаю что вы именно разрабатываете, если для частных пользователей то скорее всего такое нормально.
Если для крупного бизнеса, то там часто попадается что уже есть ИТ инфраструктура , куплены лицензии и надо подстраиваться под условия.
Мало кто согласится при наличии Oracle и штата специалистов Oracle еще заводить дополнительно спецов по MSSQL чтобы поддерживать решение только ради вашего софта.
Причем вполне может оказаться что у него еще и Oracle/MSSQL старый и чтобы не сломать работу других лучше написать

Msql2000Repository : IRepository
{
}


который бы гарантировал что любые изменения в нем никак не коснуться остальных версий.


S>Link2db вообще не очень претендовал на универсальность. Он претендует на то, чтобы реальным разработчикам писать реальный код. Без компромиссов вроде "пишем быстро, но код говно", и "работает приемлемо, но 80% кода — бойлерплейт".


С linq2db тут как раз получаются те компромисы что ты назвал — пишем быстро и забываем о том как оно в конечном счете на базах работать будет.
Если код красив на Linq, он может вполне быть не красив с т.з. правильного SQL для конкретной СУБД.
В итоге оно работает приемлимо, но далеко не оптимально и на нагрузках быстро всплывет.


O>>Если только использовать самые простые конструкции.

O>>Напомню — CONNECT BY LEVEL как раз позволит быстро написать код, который делает иерархический запрос, но это будет не универсано.
S>Конечно. Правильный способ — использовать ансишный CTE, который работает более-менее в любой СУБД, выпущенной после 2010.


O>>Тут противоречие как только у нас появляется специфичный код, так сразу рисуется репозиторий.

S>Мы с вами, по-видимому, по-разному понимаем термин "репозиторий".
Возможно, но я приводил пример что я под этим понимаю. Как видите реализацию специфичного кода для каждой субд и возможность переключения субд в настройках ?


O>>Либо не должно быть специфики тогда можно обойтись "упрощенкой" в виде linq2db.

S> вообще, link2db достаточно умный, чтобы автоматически порождать адекватные идиомы SQL. Скажем, поддержка иерархических запросов через CTE в нём есть.
В нем даже нейронки нету чтобы быть умнее человека Я понимаю тем кто не хочет SQL особо знать это удобнее, но в конечном итоге знать придется не только SQL но и специфику СУБД.

S>В то, что оракл требует хинтов на каждый чих, лично я не верю — не может он быть настолько отстоем.

S>Это означает, что у реального приложения на 1000 запросов будет два-три десятка таких, которым потребовались хинты. Подход "с репозиторием" будет означать наличие 1000 методов, из которых только 20-30 имеют нетривиальную реализацию.
Как только появляется специфика это уже будет репозиторий, как я писал выше приведите пример как видится специфичная реалзация.

S>Болезнь "CRUD-хранимки", вид сбоку. Linq позволит написать 1000 запросов в лоб и взлететь, а потом подтюнить ровно те 20-30, которые того заслуживают.

В лоб не получится, т.к. писать без понимания ( а понимание сразу не появится ) как оно транслируется и ложится на SQL, чревато посиделками в духе — написано же все правильно, почему же оно выдает ошибку или генерит не тот SQL который ожидался.

O>>Может быть верно в частном случае, но во первых хинты не только в первом select может быть а во всех вложенных, во вторых разные субд требуют немного по разному реализовывать запросы которые бы работали оптимально.

O>>Условно где-то лучше написать select * from а where a.id in ( select * from b ) , а где-то with b select a in b, это так "псевдо sql" думаю понятно о чем речь.
S>Такие вещи link2db отрабатывает сам, из коробки.

А код он сам не пишет случаем ?
Не думаю. Может одиночный подзапрос в with конечно он и разложит сам, но не всегда это нужно, а сообразить лучше человека, когда надо, а когда нет он не сможет.
И я опять же хочу обратить внимание что я привожу примеры не то что вот конкретная беда есть именно с одиночным вложенным запросом, а в целом что запросы требуется писать разные для оптимальной работы.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 18.04.2019 11:55 okon . Предыдущая версия .
Re[21]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 11:53
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, okon, Вы писали:


D>>>Это высосано из пальца. Ничего не съедет. Съедет когда вы в вашем базовом (гипотетическом) репозитории что-то докрутили.

O>>Ну в моем случае может и не быть базового, зависит от вашего разумного выбора что и как будет меняться.
O>>А в случае linq2db, получается общий код и любая правка или изменение структуры запроса требует тестирования на всех базах.
·>Ты немного в не ту сторону думаешь. Тут ведь как. Есть некое приложение, которое должно работать во всех базах. По сути три подхода
·>1. иметь свой код на каждую базу
·>2. иметь общий код на все базы
·>3. иметь общий код на все базы и возможность кастомизировать под конкретную.

·>(1) хорош когда у тебя очень много заточки под каждую конкретную базу для вылизывания производительности. Как правило, относительно редкий случай.

·>(2) хорош когда у тебя много бизнес-кода и проект развивается. И приходится в угоду общности жертвовать производительностью. "Давайте добавим новое поле в Аккаунт" — более типично, чем "ой, у нас оракл притормаживает на данной операции, давайте добавлять хинты и хранимки". Поэтому чаще всего получается "любая правка" будет изменением бизнес-требований, а значит гораздо важнее иметь возможность поменять одно место в коде и потом просто протестировать на всех базах, чем менять код под каждую из баз и потом тоже так же всё тестировать.
·>А (3) это комбинация (1) и (2) — компромис и часто результат развития варианта (2).

Все верно я и не говорю что linq2db это в каких то простых случаях плохо.
Если надо ( утрирую ) select * from users сделать где 10 пользователей, то почему бы и нет, зачем вникать в то как работает СУБД и изучать SQL.

Но когда база относительно большая то проблема производительности там выходит на первый план, т.к. когда много мелких бизнес операций и каждая тормозит незаметно пусть по полсекунды, но в сумме получаются минуты.
А потом ты сидишь в какой-нибудь конторе и думаешь а чего это тетенька уже полчаса тупит за компьютером и не может мне просто бумажку распечатать.
Как правило такие проблемы сильно тормозят бизнес, вместо 10 клиентов успевают обслужить например 8 , уже потери 20%.
бизнес функции тоже требуются конечно, но их уже проектируешь с мыслями о том как бы добавить чтобы не сломать текущие оптимизации.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[22]: Архитектура доступа к бд
От: · Великобритания  
Дата: 18.04.19 12:58
Оценка:
Здравствуйте, okon, Вы писали:

O>Но когда база относительно большая то проблема производительности там выходит на первый план, т.к. когда много мелких бизнес операций и каждая тормозит незаметно пусть по полсекунды, но в сумме получаются минуты.

У тебя всё равно где-то будет абстракция, которая оптимальные в данной базе запросы будет выражать в виде одной бизнес-операции.

O>А потом ты сидишь в какой-нибудь конторе и думаешь а чего это тетенька уже полчаса тупит за компьютером и не может мне просто бумажку распечатать.

O>Как правило такие проблемы сильно тормозят бизнес, вместо 10 клиентов успевают обслужить например 8 , уже потери 20%.
O>бизнес функции тоже требуются конечно, но их уже проектируешь с мыслями о том как бы добавить чтобы не сломать текущие оптимизации.
Чаще выбор в том, чтобы можно было в принципе обслужить хотя бы 8 из 10 клиентов, каждый с их уникальным сценарием. А не только двух, а остальных вручную кастомизировать, т.к. "компьютер сказал нет".
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: Архитектура доступа к бд
От: Ночной Смотрящий Россия  
Дата: 18.04.19 13:08
Оценка: +2
Здравствуйте, okon, Вы писали:

O> дело не только в хинтах ( которые не только в начале запроса могут быть ), структура запроса, специфичные для субд операторы для запроса в теле.


Тебе вроде уже ответили, что большое количество такой специфики linq2db умеет сам, а оставшиеся кейсы не стоят того огромного бойлерплейтного кода, что ты предлагаешь.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[18]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 18.04.19 16:01
Оценка:
Здравствуйте, okon, Вы писали:

[skip]

O>>>Либо не должно быть специфики тогда можно обойтись "упрощенкой" в виде linq2db.

S>> вообще, link2db достаточно умный, чтобы автоматически порождать адекватные идиомы SQL. Скажем, поддержка иерархических запросов через CTE в нём есть.
O>В нем даже нейронки нету чтобы быть умнее человека Я понимаю тем кто не хочет SQL особо знать это удобнее, но в конечном итоге знать придется не только SQL но и специфику СУБД.

linq2db сделан для людей которые знают SQL не понаслышке, он застваляет писать SQL, но только посредством LINQ.

S>>В то, что оракл требует хинтов на каждый чих, лично я не верю — не может он быть настолько отстоем.

S>>Это означает, что у реального приложения на 1000 запросов будет два-три десятка таких, которым потребовались хинты. Подход "с репозиторием" будет означать наличие 1000 методов, из которых только 20-30 имеют нетривиальную реализацию.
O>Как только появляется специфика это уже будет репозиторий, как я писал выше приведите пример как видится специфичная реалзация.

S>>Болезнь "CRUD-хранимки", вид сбоку. Linq позволит написать 1000 запросов в лоб и взлететь, а потом подтюнить ровно те 20-30, которые того заслуживают.

O>В лоб не получится, т.к. писать без понимания ( а понимание сразу не появится ) как оно транслируется и ложится на SQL, чревато посиделками в духе — написано же все правильно, почему же оно выдает ошибку или генерит не тот SQL который ожидался.

Опять же, что значит как ложится в SQL. Как LINQ написали, так они и строит SQL, проводя еще массу оптимизаций сиквела.

O>>>Может быть верно в частном случае, но во первых хинты не только в первом select может быть а во всех вложенных, во вторых разные субд требуют немного по разному реализовывать запросы которые бы работали оптимально.

O>>>Условно где-то лучше написать select * from а where a.id in ( select * from b ) , а где-то with b select a in b, это так "псевдо sql" думаю понятно о чем речь.
S>>Такие вещи link2db отрабатывает сам, из коробки.

O>А код он сам не пишет случаем ?

O>Не думаю. Может одиночный подзапрос в with конечно он и разложит сам, но не всегда это нужно, а сообразить лучше человека, когда надо, а когда нет он не сможет.
O>И я опять же хочу обратить внимание что я привожу примеры не то что вот конкретная беда есть именно с одиночным вложенным запросом, а в целом что запросы требуется писать разные для оптимальной работы.

Вы что-то приписываете linq2db не понимая как он работает. Поставит он вам WITH куда надо. Только надо написать что вам нужен CTE https://linq2db.github.io/articles/sql/CTE.html.
Re[19]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 18:14
Оценка:
O>>В нем даже нейронки нету чтобы быть умнее человека Я понимаю тем кто не хочет SQL особо знать это удобнее, но в конечном итоге знать придется не только SQL но и специфику СУБД.
D>linq2db сделан для людей которые знают SQL не понаслышке, он застваляет писать SQL, но только посредством LINQ.
Сделан возможно да, но часто им пользуются не понимая,
вот кстати местный форумчанин также описал проблемы о которых я говорю.
https://habr.com/ru/post/230479/


O>>В лоб не получится, т.к. писать без понимания ( а понимание сразу не появится ) как оно транслируется и ложится на SQL, чревато посиделками в духе — написано же все правильно, почему же оно выдает ошибку или генерит не тот SQL который ожидался.

D>Опять же, что значит как ложится в SQL. Как LINQ написали, так они и строит SQL, проводя еще массу оптимизаций сиквела.
Это вопрос был к коллеге выше который написал что в моем случае linq2db умный и сам догадается когда with сделать, а когда без with.
А я спашиваю про то что если я напишу в Linq select * from ( select ) то какой запрос SQL оно сделает ? с With или без ? будет ли учитывать особенность БД что данный запрос на данных таблицах лучше выполнить с with ?
конечно скорее всего нет не будет.
Поэтому мне нужно будет один Linq написать как select * from a in (select from b ) , а для другой базы сделать как (select from b).concat(select from a) , чтобы получился запрос с WITH.
оптимальной работы.

D>Вы что-то приписываете linq2db не понимая как он работает. Поставит он вам WITH куда надо. Только надо написать что вам нужен CTE https://linq2db.github.io/articles/sql/CTE.html.

Ну вот я собственно про то же что надо прописать в одном случае что нужен, для другой базы что не нужен. В итоге получаем для метода void DoSomething() две разных реализации, в зависимости от СУБД.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[23]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 18:21
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, okon, Вы писали:


O>>Но когда база относительно большая то проблема производительности там выходит на первый план, т.к. когда много мелких бизнес операций и каждая тормозит незаметно пусть по полсекунды, но в сумме получаются минуты.

·>У тебя всё равно где-то будет абстракция, которая оптимальные в данной базе запросы будет выражать в виде одной бизнес-операции.
Ну собственно про это и речь, не важно как ее назвать, я ее называю IRepository.
По сути она и будет предоставлять доступ к данным, а реализация для каждой СУБД своя, или про что хотели сказать ?

O>>бизнес функции тоже требуются конечно, но их уже проектируешь с мыслями о том как бы добавить чтобы не сломать текущие оптимизации.

·>Чаще выбор в том, чтобы можно было в принципе обслужить хотя бы 8 из 10 клиентов, каждый с их уникальным сценарием. А не только двух, а остальных вручную кастомизировать, т.к. "компьютер сказал нет".
Под клиентами я понимаю тут не самого заказчика ПО, а людей которые пользуются бизнесом заказчика. Чем медленнее его ПО работает, тем меньше клиентов он обслуживает.
И требования производительности имеют важное значение, например те же банки.
Не оптимальный но рабочий запрос на демо примере позволит вам да быстрее охмурить заказчика , но в итоге все равно придется переделывать если потребуется производительность.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[20]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 18.04.19 19:46
Оценка: +1
Здравствуйте, okon, Вы писали:


O>>>В нем даже нейронки нету чтобы быть умнее человека Я понимаю тем кто не хочет SQL особо знать это удобнее, но в конечном итоге знать придется не только SQL но и специфику СУБД.

D>>linq2db сделан для людей которые знают SQL не понаслышке, он застваляет писать SQL, но только посредством LINQ.
O>Сделан возможно да, но часто им пользуются не понимая,
O>вот кстати местный форумчанин также описал проблемы о которых я говорю.
O>https://habr.com/ru/post/230479/

Если честно, то как раз наоборот. Люди понимают что пишут, время от времени появляются субьекты которые думают обьектами — или отпадают или меняют мировозрение.


O>>>В лоб не получится, т.к. писать без понимания ( а понимание сразу не появится ) как оно транслируется и ложится на SQL, чревато посиделками в духе — написано же все правильно, почему же оно выдает ошибку или генерит не тот SQL который ожидался.

D>>Опять же, что значит как ложится в SQL. Как LINQ написали, так они и строит SQL, проводя еще массу оптимизаций сиквела.
O>Это вопрос был к коллеге выше который написал что в моем случае linq2db умный и сам догадается когда with сделать, а когда без with.
O>А я спашиваю про то что если я напишу в Linq select * from ( select ) то какой запрос SQL оно сделает ? с With или без ? будет ли учитывать особенность БД что данный запрос на данных таблицах лучше выполнить с with ?
O>конечно скорее всего нет не будет.
O>Поэтому мне нужно будет один Linq написать как select * from a in (select from b ) , а для другой базы сделать как (select from b).concat(select from a) , чтобы получился запрос с WITH.
O>оптимальной работы.

Это все исключения, и из-за них я никогда не буду генерить репозиторий, а придумаю более элегантное решение.

D>>Вы что-то приписываете linq2db не понимая как он работает. Поставит он вам WITH куда надо. Только надо написать что вам нужен CTE https://linq2db.github.io/articles/sql/CTE.html.

O>Ну вот я собственно про то же что надо прописать в одном случае что нужен, для другой базы что не нужен. В итоге получаем для метода void DoSomething() две разных реализации, в зависимости от СУБД.

У меня сложилось мнение что вы пробуете мне рассказать очевидные вещи. Я вам еще раз говорю: напишите эффективно сразу, а потом ищите как это унифицировать. Очень сильно сомневаюсь что вы будеде использовать Firebird, или еще какой угар не поддерживающий стандарты.
Re: Архитектура доступа к бд
От: bnk СССР http://unmanagedvisio.com/
Дата: 18.04.19 19:58
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Есть старое веб формс приложение, работающее с ms sql. В нем запросы для доступа к бд хранятся в классах в виде строк и в них же при необходимости формируются.

BE>Теперь нужно добавить работу с postgre sql.
BE>Я понимаю, что это классический случай применения Entity Framework, но в данном случае это будет означать с нуля переписать всю работу с бд. А работу с ms sql трогать нельзя и нужно продолжать развивать.

BE>Пока не придумали ничего лучше чем писать:

BE>
BE>if (mssql)
BE>{
BE>    return mssqlQuery;
BE>}
BE>else
BE>{
BE>    return postgresQuery;
BE>}
BE>


Если не переделывать (не переводить на Linq), то IMHO, это волне себе рабочий вариант. Перепишешь сотню квери, и все пучком.
По крайней мере гарантируешь что работа с MSSQL не сломается.
Re[21]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 20:00
Оценка:
D>Если честно, то как раз наоборот. Люди понимают что пишут, время от времени появляются субьекты которые думают обьектами — или отпадают или меняют мировозрение.
Если люди хорошо понимают SQL то им удобнее сразу видеть запрос и писать на SQL. Если еще они хорошо разбираются в специфике конкретной СУБД то им также удобнее видеть и редактировать конечный запрос.
Также как вам удобнее читать и выражать мысли на родном языке который вы знаете лучше чем иностранный.


D>Это все исключения, и из-за них я никогда не буду генерить репозиторий, а придумаю более элегантное решение.

Я бы не назвал это исключениями, когда начинаешь разбираться с конкретной СУБД, то использование ее специфики единственный способ делать эффективные решения.
А какое может быть элегантное решение ? уже помоему все все перепробовали и в таких случаях самое элегантное, везде где требуется разное поведение у единого интерфейса пропагандируется IoC подход.
Как кстати вы обеспечиваете юнит тесты для реализации с linq2db ?


D>>>Вы что-то приписываете linq2db не понимая как он работает. Поставит он вам WITH куда надо. Только надо написать что вам нужен CTE https://linq2db.github.io/articles/sql/CTE.html.

O>>Ну вот я собственно про то же что надо прописать в одном случае что нужен, для другой базы что не нужен. В итоге получаем для метода void DoSomething() две разных реализации, в зависимости от СУБД.
D>У меня сложилось мнение что вы пробуете мне рассказать очевидные вещи. Я вам еще раз говорю: напишите эффективно сразу, а потом ищите как это унифицировать. Очень сильно сомневаюсь что вы будеде использовать Firebird, или еще какой угар не поддерживающий стандарты.
Вещи конечно очевидные, мне поэтому не совсем понятно почему эта дискуссия так затягивается.
Напишите эффективно сразу — это значит будет 2 реализации DoSomethingOracle, DoSomethingMSSQL, а точнее будет две реализации IRepository.
Напишите унифицировано — это значит будет 1 метод DoSomething , но далеко не всегда эффективный.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[24]: Архитектура доступа к бд
От: · Великобритания  
Дата: 18.04.19 20:23
Оценка: +1
Здравствуйте, okon, Вы писали:

O>>>Но когда база относительно большая то проблема производительности там выходит на первый план, т.к. когда много мелких бизнес операций и каждая тормозит незаметно пусть по полсекунды, но в сумме получаются минуты.

O>·>У тебя всё равно где-то будет абстракция, которая оптимальные в данной базе запросы будет выражать в виде одной бизнес-операции.
O>Ну собственно про это и речь, не важно как ее назвать, я ее называю IRepository.
O>По сути она и будет предоставлять доступ к данным, а реализация для каждой СУБД своя, или про что хотели сказать ?
IRepository слишком специфично. "A repository is an abstraction which represents any underlying and arbitrary data store as if it were an in memory collection of objects". Или ты не то так называешь.

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

Ага. Вот только слово "если" — тут ключевое. Premature optimisation, слыхал?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[25]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 20:32
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, okon, Вы писали:


O>>>>Но когда база относительно большая то проблема производительности там выходит на первый план, т.к. когда много мелких бизнес операций и каждая тормозит незаметно пусть по полсекунды, но в сумме получаются минуты.

O>>·>У тебя всё равно где-то будет абстракция, которая оптимальные в данной базе запросы будет выражать в виде одной бизнес-операции.
O>>Ну собственно про это и речь, не важно как ее назвать, я ее называю IRepository.
O>>По сути она и будет предоставлять доступ к данным, а реализация для каждой СУБД своя, или про что хотели сказать ?
·>IRepository слишком специфично. "A repository is an abstraction which represents any underlying and arbitrary data store as if it were an in memory collection of objects". Или ты не то так называешь.

Не совсем понятно что имелось ввиду "как бы представленно коллекцией в памяти" я говорю про то что мы описываем интерфейс для доступа к данным,
и делаем реализацию специфичную для СУБД.


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

·>Ага. Вот только слово "если" — тут ключевое. Premature optimisation, слыхал?
Она может быть Premature на начальном этапе разработки, к концу разработки или после начала промышленной эксплуатации это становиться уже скорее ежедневной рутиной задачи на оптимизацию.
Т.е. как бы вы не выражали свой SQL через linq2db или другим способом — появится специфика и потребуется разделение реализации для каждой субд, причем еще как правило для версий СУБД.
Например в более современных можно использовать новые возможности , которые нельзя делать на старых базах.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[22]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 18.04.19 22:19
Оценка:
Здравствуйте, okon, Вы писали:

D>>Если честно, то как раз наоборот. Люди понимают что пишут, время от времени появляются субьекты которые думают обьектами — или отпадают или меняют мировозрение.

O>Если люди хорошо понимают SQL то им удобнее сразу видеть запрос и писать на SQL. Если еще они хорошо разбираются в специфике конкретной СУБД то им также удобнее видеть и редактировать конечный запрос.
O>Также как вам удобнее читать и выражать мысли на родном языке который вы знаете лучше чем иностранный.

Вы можете на SQL делать query decomposition? Вы можете безшовно обьединить два запроса, а потом из этой всей каши оптимально взять только одно поле?
Что случится с вашими запросами если DBA решит переименовать поле или тип?


D>>Это все исключения, и из-за них я никогда не буду генерить репозиторий, а придумаю более элегантное решение.

O>Я бы не назвал это исключениями, когда начинаешь разбираться с конкретной СУБД, то использование ее специфики единственный способ делать эффективные решения.
O>А какое может быть элегантное решение ? уже помоему все все перепробовали и в таких случаях самое элегантное, везде где требуется разное поведение у единого интерфейса пропагандируется IoC подход.
O>Как кстати вы обеспечиваете юнит тесты для реализации с linq2db ?

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


D>>>>Вы что-то приписываете linq2db не понимая как он работает. Поставит он вам WITH куда надо. Только надо написать что вам нужен CTE https://linq2db.github.io/articles/sql/CTE.html.

O>>>Ну вот я собственно про то же что надо прописать в одном случае что нужен, для другой базы что не нужен. В итоге получаем для метода void DoSomething() две разных реализации, в зависимости от СУБД.
D>>У меня сложилось мнение что вы пробуете мне рассказать очевидные вещи. Я вам еще раз говорю: напишите эффективно сразу, а потом ищите как это унифицировать. Очень сильно сомневаюсь что вы будеде использовать Firebird, или еще какой угар не поддерживающий стандарты.
O>Вещи конечно очевидные, мне поэтому не совсем понятно почему эта дискуссия так затягивается.
O>Напишите эффективно сразу — это значит будет 2 реализации DoSomethingOracle, DoSomethingMSSQL, а точнее будет две реализации IRepository.
O>Напишите унифицировано — это значит будет 1 метод DoSomething , но далеко не всегда эффективный.

Ну чушь же. Вы когда дошли до того что надо использовать хинты? Профилируя конечно. В 95% сиквел работает с однаковой эффективностью на всех базах. Сджоинить толпу таблиц, сгруппировать и так далее.
И я не про DoSomethig, а дай мне Something и не листом, а IQueryable и потом переиспользуя это в других запросах в комбинации с другими фильтрами. Да и чтобы лишние джоины пооткидывало если данные от них не нужны в текущей проекции, а на результат выборки они не влияют.

Я говорю вам про конструктор запросов, клейте их как угодно и linq2db попробует это разрулить.
Re[23]: Архитектура доступа к бд
От: okon  
Дата: 18.04.19 22:53
Оценка: -1
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, okon, Вы писали:


D>>>Если честно, то как раз наоборот. Люди понимают что пишут, время от времени появляются субьекты которые думают обьектами — или отпадают или меняют мировозрение.

O>>Если люди хорошо понимают SQL то им удобнее сразу видеть запрос и писать на SQL. Если еще они хорошо разбираются в специфике конкретной СУБД то им также удобнее видеть и редактировать конечный запрос.
O>>Также как вам удобнее читать и выражать мысли на родном языке который вы знаете лучше чем иностранный.

D>Вы можете на SQL делать query decomposition? Вы можете безшовно обьединить два запроса, а потом из этой всей каши оптимально взять только одно поле?

А какие с этим проблемы есть ?
Про одно поле тоже не понял проблему , точнее как linq2db поможет взять оптимально, а обычный запрос не поможет. Ведь в итоге выполнится обычный запрос который можно сразу и написать.

D>Что случится с вашими запросами если DBA решит переименовать поле или тип?

Ничего хорошего не случиться если он по своей инициативе переименует. А как от этого защищает link2db ?
Разделение реализации в этом случае скорее помогает если на Oracle поле решили переименовать ( то мы переименуем именно в оракловой реализации ), а в MSSQL останется прежним.

O>>Как кстати вы обеспечиваете юнит тесты для реализации с linq2db ?


D>Сколько бы ежики не тыкались в кактус, лучшего теста здесь, чем функциональное тестирование тут я не вижу. Тестовая база с набитыми данными. Моканье только тестирует сделали ли вы вставку или апдейт или нет. Масло масленное в общем.


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

O>>Вещи конечно очевидные, мне поэтому не совсем понятно почему эта дискуссия так затягивается.

O>>Напишите эффективно сразу — это значит будет 2 реализации DoSomethingOracle, DoSomethingMSSQL, а точнее будет две реализации IRepository.
O>>Напишите унифицировано — это значит будет 1 метод DoSomething , но далеко не всегда эффективный.

D>Ну чушь же. Вы когда дошли до того что надо использовать хинты? Профилируя конечно. В 95% сиквел работает с однаковой эффективностью на всех базах. Сджоинить толпу таблиц, сгруппировать и так далее.


Зависит от того с чего я начал, с каким объемом вы работаете, если в небольших то да в 95% вы просто не заметите не эффективности в запросах и будет казаться что все хорошо.
Если объемы данных велики и база и логика сложные, то у вас в каждом втором запросе нужны будут и хинты и другая специфика СУБД.

D>И я не про DoSomethig, а дай мне Something и не листом, а IQueryable и потом переиспользуя это в других запросах в комбинации с другими фильтрами. Да и чтобы лишние джоины пооткидывало если данные от них не нужны в текущей проекции, а на результат выборки они не влияют.


Ну и в итоге вы берете некий IQueryable который уже как "черный ящик" , накладывате на него еще запросы и скрещиваете пальцы что щас вам linq2db разрулит все сам и даст лучший запрос.
Не понимая какой запрос в итоге получится что на самом деле откинется, а что нет, если будет несколько таких вложенных запросов.

Если вы про эту "декомпозицию" имели ввиду , то нет, я лучше GetCats() GetDogs() напишу отдельные запросы четко наглядно было видно как они работают,
пусть даже там окажется какой-то общий подзапрос, он вполне может оказаться не общим через какое-то время. Так будет намного безопаснее для изменений в будущем.

D>Я говорю вам про конструктор запросов, клейте их как угодно и linq2db попробует это разрулить.


Да именно что попробует.

Тоже самое можно сказать про переводчики — да пишите как хотите, там само все переведется.
Да переведется и даже будет вероятно понятно и работать, но качество на чуть сложных предложениях будет существенно уступать человеческому переводу на конкретный язык.
Тоже самое с запросами к конкретной базе.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[18]: Архитектура доступа к бд
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.04.19 04:51
Оценка:
Здравствуйте, okon, Вы писали:

O>Репозиторий — универсально ? Да не, я бы сказал что наоборот, в идеале я бы сделал для каждой субд свой изолированный код.

Ну, вы только что предлагали впилить в репозиторий GetNewId, который гарантирует проблемы с производительностью в тех СУБД, где нет встроенной поддержки генераторов. А в тех СУБД, где поддержка генераторов есть, его реализация тривиальна, и не добавляет никакой пользы.

O>Не суть до чего дойдет мыслительный процесс, важно в итоге родится некий метод DoSomething() который должен использоваться бизнес-логикой и эта логика не должна знать специфику СУБД.

Да, в link2db сообщают о наличии InsertWithIdentity.
O>В котором досаточно часто может потребоваться специфичная функция как для оптимальной работы так и для того чтобы вприцнипе работало на данной СУБД.
O>Ну повезло, не знаю что вы именно разрабатываете, если для частных пользователей то скорее всего такое нормально.
O>Если для крупного бизнеса, то там часто попадается что уже есть ИТ инфраструктура , куплены лицензии и надо подстраиваться под условия.
Ну, наши потребители — это мелкие бизнесы вроде Dell, Telefonica/O2, Telstra и прочие компании из списка top 500.
O>Мало кто согласится при наличии Oracle и штата специалистов Oracle еще заводить дополнительно спецов по MSSQL чтобы поддерживать решение только ради вашего софта.
Зависит от специфики софта. Любой мало-мальски крупный софт всё равно требует поддержки от производителя. Т.е. в нашу базу никто не лезет, кроме нашего же саппорта.
O>Причем вполне может оказаться что у него еще и Oracle/MSSQL старый и чтобы не сломать работу других лучше написать
O>который бы гарантировал что любые изменения в нем никак не коснуться остальных версий.
Ну, я не собираюсь вас агитировать за поддержку ровно одной СУБД. Вы можете и слой изоляции над СУБД нарисовать, но речь о том, что на link2db вам это будет сделать проще и качественнее, чем на чём-либо ещё.

O>С linq2db тут как раз получаются те компромисы что ты назвал — пишем быстро и забываем о том как оно в конечном счете на базах работать будет.

Нет.
O>Если код красив на Linq, он может вполне быть не красив с т.з. правильного SQL для конкретной СУБД.
Нет.
O>В итоге оно работает приемлимо, но далеко не оптимально и на нагрузках быстро всплывет.
Это было бы правдой, если бы link2db был написан по-другому. На практике его генератор SQL — лучший в индустрии.
Его даже рукопашным написанием sql тяжело обставить.

O>Возможно, но я приводил пример что я под этим понимаю. Как видите реализацию специфичного кода для каждой субд и возможность переключения субд в настройках ?

O>В нем даже нейронки нету чтобы быть умнее человека Я понимаю тем кто не хочет SQL особо знать это удобнее, но в конечном итоге знать придется не только SQL но и специфику СУБД.
Конечно же нужно знать и SQL и специфику СУБД. Link2db — это лучший способ писать SQL. Не заменить SQL, а именно писать SQL эффективно — как с точки зрения человека, так и с точки зрения СУБД.

O>Как только появляется специфика это уже будет репозиторий, как я писал выше приведите пример как видится специфичная реалзация.

Ну, я вроде бы приводил пример того, как видится специфичная реализация.
S>>Болезнь "CRUD-хранимки", вид сбоку. Linq позволит написать 1000 запросов в лоб и взлететь, а потом подтюнить ровно те 20-30, которые того заслуживают.
O>В лоб не получится, т.к. писать без понимания ( а понимание сразу не появится ) как оно транслируется и ложится на SQL, чревато посиделками в духе — написано же все правильно, почему же оно выдает ошибку или генерит не тот SQL который ожидался.
В теории — да. На практике — нет.

O>А код он сам не пишет случаем ?

Код sql — да, сам.

O>Не думаю. Может одиночный подзапрос в with конечно он и разложит сам, но не всегда это нужно, а сообразить лучше человека, когда надо, а когда нет он не сможет.

Все такие вещи описываются в драйвере конкретной СУБД в link2db.

O>И я опять же хочу обратить внимание что я привожу примеры не то что вот конкретная беда есть именно с одиночным вложенным запросом, а в целом что запросы требуется писать разные для оптимальной работы.

Не бывает "в целом". Бывают конкретные проблемы, которые решаются конкретными способами. Например, в каждом диалекте SQL по своему сделана реализация постраничного вывода. Link2db выбирает идиоматический способ для каждого диалекта (включая версии движков). Бывают СУБД, которые не умеют семантическую оптимизацию запросов — например, устранение избыточных join при наличии foreign key constraint добавили только в одной из недавних версий MS SQL.
Link2db сам делает такую оптимизацию при генерации SQL.
Вы недооцениваете его мощь
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[24]: Архитектура доступа к бд
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.04.19 05:31
Оценка: 30 (3)
Здравствуйте, okon, Вы писали:

D>>Вы можете на SQL делать query decomposition? Вы можете безшовно обьединить два запроса, а потом из этой всей каши оптимально взять только одно поле?

O>А какие с этим проблемы есть ?
Очень простые. SQL не спроектирован для декомпозиции.
Классическая задача, о которую спотыкаются все: сделать row-level security. В простейшем случае у нас есть таблица вида
create table Permissions
{
  TableName varchar(max),
  RowId int,
  UserId int not null foreign key Users(Id) on delete cascade,
  bit CanRead,
  bit CanUpdate
}

Все запросы на чтение должны работать примерно так:
select * from Document

=>
select Document.* from Document inner join Permissions on Document.Id = Permission.RowId and Permission.TableName = 'Document' and UserId = @CurrentUser
where Permissions.CanRead = 1

Вы не сможете написать на SQL мета-функцию, которая бы возвращала отфильтрованный датасет для любой таблицы.
Либо вы будете писать 2000 TVF вида GetAllowedDocuments, GetAllowedStores, GetAllowedPersons и так далее.
Либо вы будете клеить SQL в текстовом виде, получая сложности в отладке и субоптимальные запросы в клинических случаях.
Linq позволяет вам написать такую мета-функцию, которая получает на вход IQueryable<T> where T: IEntityWithID, а на выход отдаёт IQueryable<T> с наложенным предикатом.
И она будет гарантированно корректной.
O>Про одно поле тоже не понял проблему , точнее как linq2db поможет взять оптимально, а обычный запрос не поможет. Ведь в итоге выполнится обычный запрос который можно сразу и написать.
Проблемы возникают из-за того, что в репозитории уже есть метод GetPeople(), который делает select * from people.
Там, где вам потребовался FullName и Email, вы встаёте перед дилеммой:
1. Взять готовый GetPeople(), и использовать только FullName и Email
2. Добавить в репозиторий новый метод GetPeopleNameWithEmailOnly().
Будете ли вы делать второе? А с учётом того, что у вас этих репозиториев — 20 штук, по одному на каждую версию СУБД?
Практика показывает, что скорее всего — нет. Разработчик идёт по пути наименьшего сопротивления и использует то, что уже есть. Его задача — написать одну конкретную страничку. Ему никто не ставил задачу расширять репозиторий.
В большом коллективе у него и прав-то может не оказаться на правку ядра системы. Или права есть, но code review займёт вдвое дольше.
Link2db позволяет не мучиться выбором, а просто написать var q = from db.People select FullName, Email.
Это не требует никаких дополнительных затрат усилий, и при этом результирующий SQL будет максимально эффективен.
Можно позволить себе реализовать "оригинальный" People в виде адского Join из десятка таблиц, чтобы дать лёгкий доступ ко всем редкоиспользуемым свойствам — и это не ухудшит производительность проекций, разбросанных по всей системе.
И не увеличит количество прикладного кода или площадь поверхности репозитория.

O>Ничего хорошего не случиться если он по своей инициативе переименует. А как от этого защищает link2db ?

Очень просто. Так как запросы хранятся в виде статически типизированного кода, а не в виде текстовых строчек, то простейший refactoring tool (в том числе и встроенный в VS) автоматически найдёт и переименует все использования данного поля.
O>Тесты разные нужны тесты разные важны, юнит тесты нужны для моментальной проверки в момент разработки. Они должны быть замоканы по определению иначе будут тормозить.
Я всё жду, когда мне покажут минимально полезный юнит тест для системы на основе link2db.
Для рукопашного SQL юнит тесты важны и нужны, т.к. там можно просто облажаться в строковом запросе, и ждать прогона на настоящей БД для получения syntax error near ( — шибко дорого.
То, что в рукопашном SQL ловят юнит тесты, link2db ловит ещё до компиляции проекта, подчёркивая красным неверные места.
А осмысленные тесты, вроде того, что мы не перепутали направление ">" при сравнении даты, всё же эффективнее гонять на реальной тестовой базе.
O>Тестирование на данных приближенных к реальным тоже важно, но оно длительное по времени и запускается уже когда разработчик считает что функционал закончен и все юнит тесты выполнились успешно.

O>>>Вещи конечно очевидные, мне поэтому не совсем понятно почему эта дискуссия так затягивается.

O>Зависит от того с чего я начал, с каким объемом вы работаете, если в небольших то да в 95% вы просто не заметите не эффективности в запросах и будет казаться что все хорошо.
O>Если объемы данных велики и база и логика сложные, то у вас в каждом втором запросе нужны будут и хинты и другая специфика СУБД.
Ещё раз: никто (в здравом уме) не пишет хинты заранее, "на всякий случай". Если у вас такие люди есть — немедленно отстраните их от работы до окончания реабилитации и получения разрешения на работу от корпоративного психоаналитика.
Вся оптимизация (в том числе и в СУБД) начинается с наблюдения фактов: "метод Х выполняется дольше, чем мы хотим".
Затем идёт профилирование, в поисках конкретного узкого места — например, конкретного запроса, который тормозит на конкретных данных.
Затем идёт анализ того, почему он так тормозит. И последовательность шагов примерно такая:
— нет ли там артефактов вроде устаревшей статистики, которые мешают СУБД оптимально выполнить конкретный запрос?
— можно ли изменить семантику запроса так, чтобы он делал меньше лишней работы? (Вот тут как раз начинаются улучшения проекций и выкидывание лишних джойнов)
— можно ли улучшить запрос путём добавления индексов?
— можно ли улучшить запрос хинтами?
— можно ли улучшить запрос, построив свои собственные аналоги индексов, которые не поддерживаются нашей СУБД из коробки? (Например, распилив поле email на localpart и hostname, потому как оптимизировать like '%@hotmail.com' большинство СУБД неспособны)
Видите — хинты идут далеко не первыми даже после того, как мы убедились в необходимости оптимизации конкретного запроса.
Написание их заранее — верный способ выкопать себе яму, т.к. распределение реальных данных может сильно отличаться от фантазий разработчика. Опытнейшие люди индустрии десятилетиями полируют движки СУБД, чтобы они выбирали оптимальный план для каждого запроса. Хинт связывает руки оптимизатору, так что план, "оптимальный" на тестовых данных, может на порядок хуже исполняться на боевых.

O>Ну и в итоге вы берете некий IQueryable который уже как "черный ящик" , накладывате на него еще запросы и скрещиваете пальцы что щас вам linq2db разрулит все сам и даст лучший запрос.

O>Не понимая какой запрос в итоге получится что на самом деле откинется, а что нет, если будет несколько таких вложенных запросов.
Нет, так не получится. Если вы хотите писать эффективно работающие с СУБД приложения, нужно понимать, как работает SQL. Какие запросы должны быть написаны.
И вот в таком случае link2db даст вам возможность эффективно писать эффективный SQL.
Это как переходить с ассемблера на C++ — если вы хотите писать эффективные числодробилки, то вам надо знать всё про CPU. Все эти SSE, AVX, кэши, выравнивание, false sharing, и прочее.
Нельзя просто писать математику на С++ и скрещивать пальцы, надеясь на то, что компилятор волшебным образом напишет всё за вас.
Но при этом опытный разработчик гораздо быстрее напишет числодробилку на С++, чем на голом ассемблере — просто потому, что компилятор разворачивает "идеи" в "код" гораздо быстрее.
В простых случаях можно просто полагаться на компилятор. В сложных — приходится покурить с профайлером и дизассемблером.
Постепенно приходит понимание инструмента, и опытный разработчик сразу прикидывает, во что примерно превратится вот этот вот адский код с интринсиками и многоуровневой инстанциацией шаблонов.

O>Если вы про эту "декомпозицию" имели ввиду , то нет, я лучше GetCats() GetDogs() напишу отдельные запросы четко наглядно было видно как они работают,

O>пусть даже там окажется какой-то общий подзапрос, он вполне может оказаться не общим через какое-то время. Так будет намного безопаснее для изменений в будущем.
Это тупиковый путь.

O>Да именно что попробует.


O>Тоже самое можно сказать про переводчики — да пишите как хотите, там само все переведется.

O>Да переведется и даже будет вероятно понятно и работать, но качество на чуть сложных предложениях будет существенно уступать человеческому переводу на конкретный язык.
O>Тоже самое с запросами к конкретной базе.
Не, не то же самое. Link2db писали практики, у которых не было идеи "давайте изолируем разработчика от СУБД". У них была идея "мы хотим писать офигенный SQL, только быстрее и надёжнее, чем в хранимках или репозиториях".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Архитектура доступа к бд
От: okon  
Дата: 19.04.19 05:41
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, okon, Вы писали:


S>Ну, вы только что предлагали впилить в репозиторий GetNewId, который гарантирует проблемы с производительностью в тех СУБД, где нет встроенной поддержки генераторов. А в тех СУБД, где поддержка генераторов есть, его реализация тривиальна, и не добавляет никакой пользы.

GetNewId это совсем не про то как нужно делать реализацию, а про то что есть специфика у разных СУБД которую требуется описать специальным образом.

O>>Не суть до чего дойдет мыслительный процесс, важно в итоге родится некий метод DoSomething() который должен использоваться бизнес-логикой и эта логика не должна знать специфику СУБД.

S>Да, в link2db сообщают о наличии InsertWithIdentity.
Но логика не заключается только во вставке с идентити, а если мне нужно сначала вычислить Indentity ? потом показать его в интерфейсе, отчете, и только потом вставить значение с этим идентити.


O>>Если для крупного бизнеса, то там часто попадается что уже есть ИТ инфраструктура , куплены лицензии и надо подстраиваться под условия.

S>Ну, наши потребители — это мелкие бизнесы вроде Dell, Telefonica/O2, Telstra и прочие компании из списка top 500.

O>>Мало кто согласится при наличии Oracle и штата специалистов Oracle еще заводить дополнительно спецов по MSSQL чтобы поддерживать решение только ради вашего софта.

S>Зависит от специфики софта. Любой мало-мальски крупный софт всё равно требует поддержки от производителя. Т.е. в нашу базу никто не лезет, кроме нашего же саппорта.

Поддержка от производителя само собой. А что именно делает софт ? Какой срок по устранению дефектов стоит в договоре ? Например приходят сотрудники на работу, запускают программу и видят ошибку на экране, вы находитесь в другой часовой зоне — в какой срок по договору вы должны устранить дефект и выдать рабочую версию ?
Как решаются всякие оперативные задачи по обслуживанию базы — переустановки, бэкапы, восстановление, профилактика ?

S>Ну, я не собираюсь вас агитировать за поддержку ровно одной СУБД. Вы можете и слой изоляции над СУБД нарисовать, но речь о том, что на link2db вам это будет сделать проще и качественнее, чем на чём-либо ещё.

Возможно, про эти возможности link2db тут как дополнение обсуждается, начало ветки — это использовать разделение реализации для разных субд или же будет достаточно один универсальный метод написать.

O>>С linq2db тут как раз получаются те компромисы что ты назвал — пишем быстро и забываем о том как оно в конечном счете на базах работать будет.

S>Нет.
O>>Если код красив на Linq, он может вполне быть не красив с т.з. правильного SQL для конкретной СУБД.
S>Нет.
S>Его даже рукопашным написанием sql тяжело обставить.

Но коллега где-то тут уже приводил рассказ "чуда" что они берут функцию которая возвращает IQueryable , потом навешивают на нее еще логику, еще логику и т.д.
и потом получают чудо в виде красивого запроса. Но я же понимаю что это не так. Колелега либо вводит намеряно в заблуждение либо сам заблуждается,
может и я заблуждаюсь, но поясню почему я уверен скорее в первых двух — z понимаю же что IQueryable все что может рассказать о запросе это только expression tree и
даже человеку не достаточно этих данных чтобы написать правильный запрос.
По вашему опыту какие данные входные данные нужны для постановки задачи чтобы написать правильный запрос к субд ?

O>>Возможно, но я приводил пример что я под этим понимаю. Как видите реализацию специфичного кода для каждой субд и возможность переключения субд в настройках ?

O>>В нем даже нейронки нету чтобы быть умнее человека Я понимаю тем кто не хочет SQL особо знать это удобнее, но в конечном итоге знать придется не только SQL но и специфику СУБД.
S>Конечно же нужно знать и SQL и специфику СУБД. Link2db — это лучший способ писать SQL. Не заменить SQL, а именно писать SQL эффективно — как с точки зрения человека, так и с точки зрения СУБД.

Не совсем если ты хорошо знаешь SQL например специфику для Oracle, то для использования всего этого тебе будет очень не удобно, особенно первое время.
Когда хочешь написать хинт, а функции нет, когда хочешь вызвать функцию а ее нет либо в явном виде , либо совсем и надо писать extension.
Поэтому не получится просто сесть и начать писать если ты писал хорошо и на SQL Oracle и на Linq.

O>>Как только появляется специфика это уже будет репозиторий, как я писал выше приведите пример как видится специфичная реалзация.

S>Ну, я вроде бы приводил пример того, как видится специфичная реализация.
Ну мой вариант обозначен в моем первом ответе автору топика — http://rsdn.org/forum/dotnet/7421994.1
Автор: okon
Дата: 17.04.19

Вы с ним не согласны или просто призываете к написанию SQL на Linq2Sql ?

S>>>Болезнь "CRUD-хранимки", вид сбоку. Linq позволит написать 1000 запросов в лоб и взлететь, а потом подтюнить ровно те 20-30, которые того заслуживают.

O>>В лоб не получится, т.к. писать без понимания ( а понимание сразу не появится ) как оно транслируется и ложится на SQL, чревато посиделками в духе — написано же все правильно, почему же оно выдает ошибку или генерит не тот SQL который ожидался.
S>В теории — да. На практике — нет.
См. выше я описал типичное вхождение в Linq2Sql на практике.

O>>А код он сам не пишет случаем ?

S>Код sql — да, сам.
как уже рассмотрели выше — на основании каких входных данных ? считаете ли вы достаточным этих данных для качественного написания запроса ?


O>>Не думаю. Может одиночный подзапрос в with конечно он и разложит сам, но не всегда это нужно, а сообразить лучше человека, когда надо, а когда нет он не сможет.

S>Все такие вещи описываются в драйвере конкретной СУБД в link2db.

Даже если представить идеальный случай что в драйвере расписаны все все все детали и все бесконечное множество вариантов использования.
То в итоге написав какой-нибудь expression будет попадаться неоднозначность выбора из множества решений,
т.к. задачу можно решить разными способами, а наиболее правильный способ зависит от факторов которые в expression не фигурируют.

O>>И я опять же хочу обратить внимание что я привожу примеры не то что вот конкретная беда есть именно с одиночным вложенным запросом, а в целом что запросы требуется писать разные для оптимальной работы.

S>Не бывает "в целом". Бывают конкретные проблемы, которые решаются конкретными способами. Например, в каждом диалекте SQL по своему сделана реализация постраничного вывода. Link2db выбирает идиоматический способ для каждого диалекта (включая версии движков). Бывают СУБД, которые не умеют семантическую оптимизацию запросов — например, устранение избыточных join при наличии foreign key constraint добавили только в одной из недавних версий MS SQL.

Вот об этом и речь, а знания нужны не только о Foreign Key и индексах чтобы построить правильный запрос.

S>Link2db сам делает такую оптимизацию при генерации SQL.

S>Вы недооцениваете его мощь

Оцениваю то что он может, то что и его постоянно надо контролировать и всякими гвоздями потом прибивать если он что-то делает неправильно,
вместо того чтобы спокойно писать чистый SQL который нужно получить в итоге.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[25]: Архитектура доступа к бд
От: okon  
Дата: 19.04.19 06:45
Оценка: -1
S>
S>select Document.* from Document inner join Permissions on Document.Id = Permission.RowId and Permission.TableName = 'Document' and UserId = @CurrentUser
S>where Permissions.CanRead = 1
S>


S>Вы не сможете написать на SQL мета-функцию, которая бы возвращала отфильтрованный датасет для любой таблицы.

S>Либо вы будете писать 2000 TVF вида GetAllowedDocuments, GetAllowedStores, GetAllowedPersons и так далее.
А как это вы сделаете на Linq2Sql, тоже напишете же
GetDocuments()/GetStores(), а потом будете еще добавлять GetStores().AllowedPermissions() , не так ли ?

S>Либо вы будете клеить SQL в текстовом виде, получая сложности в отладке и субоптимальные запросы в клинических случаях.

S>Linq позволяет вам написать такую мета-функцию, которая получает на вход IQueryable<T> where T: IEntityWithID, а на выход отдаёт IQueryable<T> с наложенным предикатом.
S>И она будет гарантированно корректной.

Гарантированно корректной она конечно же не будет, откуда она возьмет данные о наличии таблицы Stores/Documents ? Из Expression ? Но там же могут быть те же опечаки Stoores, Dcments или классика
когда C русская или О путается с английской.
Также оно не сможет гарантировать что в этой таблице есть все необходимые поля.
Кто-то напишет по аналогии GetCats().AllowedPermissions(), а там нет таких полей или для Cats требуется еще указать дополнительную информацию.
Т.е. я вижу те же проблемы вид сбоку что и при написании SQL , в том числе динамического.


O>>Про одно поле тоже не понял проблему , точнее как linq2db поможет взять оптимально, а обычный запрос не поможет. Ведь в итоге выполнится обычный запрос который можно сразу и написать.

S>Проблемы возникают из-за того, что в репозитории уже есть метод GetPeople(), который делает select * from people.
S>Там, где вам потребовался FullName и Email, вы встаёте перед дилеммой:
S>1. Взять готовый GetPeople(), и использовать только FullName и Email
S>2. Добавить в репозиторий новый метод GetPeopleNameWithEmailOnly().

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

S>Будете ли вы делать второе? А с учётом того, что у вас этих репозиториев — 20 штук, по одному на каждую версию СУБД?

S>Практика показывает, что скорее всего — нет. Разработчик идёт по пути наименьшего сопротивления и использует то, что уже есть.
Это верно действительно хочется сделать попроще, иногда это действительно может оказаться выгодно. Но не всегда.

S>В большом коллективе у него и прав-то может не оказаться на правку ядра системы. Или права есть, но code review займёт вдвое дольше.

S>Link2db позволяет не мучиться выбором, а просто написать var q = from db.People select FullName, Email.
S>Это не требует никаких дополнительных затрат усилий, и при этом результирующий SQL будет максимально эффективен.

А зачем ему доступ к ядру для написания кастомного Select, он точно также может написать
$"SELECT {PEOPLE.FULLNAME}, {PEOPLE.EMAIL} FROM {PEOPLE}" также как и Linq пишем на уровне DL, не меня ничего в самой базе.

S>Можно позволить себе реализовать "оригинальный" People в виде адского Join из десятка таблиц, чтобы дать лёгкий доступ ко всем редкоиспользуемым свойствам — и это не ухудшит производительность проекций, разбросанных по всей системе.

S>И не увеличит количество прикладного кода или площадь поверхности репозитория.

O>>Ничего хорошего не случиться если он по своей инициативе переименует. А как от этого защищает link2db ?

S>Очень просто. Так как запросы хранятся в виде статически типизированного кода, а не в виде текстовых строчек, то простейший refactoring tool (в том числе и встроенный в VS) автоматически найдёт и переименует все использования данного поля.

Да но это же все равно потребуется перекомпиляция и обновление софта. Т.е. защиты нет, но согласен если SQL пишется совсем голыми строчками,
а не формируется из констант где находятся имена таблиц и полей, то рефакторинг будет ощутимо сложнее.

В таких случаях какой-нибудь SQL вынесенный в отдельный файл будет намного удобнее, по крайней мере админ сможет там переименовать поле чтобы возобновить работу.
Не дожидаясь пока разработчики на другой стороне планеты проснутся и пофиксят софт.


O>>Тесты разные нужны тесты разные важны, юнит тесты нужны для моментальной проверки в момент разработки. Они должны быть замоканы по определению иначе будут тормозить.

S>Я всё жду, когда мне покажут минимально полезный юнит тест для системы на основе link2db.
S>Для рукопашного SQL юнит тесты важны и нужны, т.к. там можно просто облажаться в строковом запросе, и ждать прогона на настоящей БД для получения syntax error near ( — шибко дорого.
S>То, что в рукопашном SQL ловят юнит тесты, link2db ловит ещё до компиляции проекта, подчёркивая красным неверные места.

А как вы пишете рукопашный SQL ? Если прямо в IDE где пишете код, то да будет проблема.
Если пишете и отлаживаете в клиенте для базы данных, то там также компилятор запроса ругнется и подсветит красным если опечатка.

И я намекаю не на юниттест самого SQL, который возможно проверить только интеграционным тестом,
а на юнит тест DAL уровня. Т.е. в случае наличия IRepository все понятно , вы делаете StubRepository в котором указываете фейковые данные.
Для того чтобы тестировать именно логику, а не запросы.
Если вы отказываетесь от IRepository то вот у меня и встает вопрос а как в этом случае пишете юнит тест для бизнес логики.
Возможно это и не к вам вопрос, т.к. об ненужности IRepository другой человек писал.

O>>Если объемы данных велики и база и логика сложные, то у вас в каждом втором запросе нужны будут и хинты и другая специфика СУБД.

S>Ещё раз: никто (в здравом уме) не пишет хинты заранее, "на всякий случай". Если у вас такие люди есть — немедленно отстраните их от работы до окончания реабилитации и получения разрешения на работу от корпоративного психоаналитика.
Прям сразу обычно да не пишут, но сначала ты пишешь в клиенте базы условно select * from table, видишь что не так мгновенно как хотелось бы,
потом понимаешь что а зачем мне * ведь нужно всего 2 поля пишешь select a,b from table,
потом понимаешь что выборка в промежуточной table же достаточно маленькая, всегда будет 1 запись пользователя, почему бы ее не закешировать в памяти СУБД и пишешь хинт на это.

Это все я условно чтобы не загромождать смысл реальными запросами которые пишутся. Т.е. не именно этот запрос является камнем преткновения.

4 действа и за 5 минут у тебя уже хороший запрос получился.
На linq2db мне каждый раз придется компилировать программу и запускать чтобы посмотреть угадал ли он что я хотел написать, итераций будет больше.
А в некоторых случаях разработка затянется т.к. он не захочет выдавать нужный мне SQL и нужно будет допиливать какой-нибудь Extension.

S>Вся оптимизация (в том числе и в СУБД) начинается с наблюдения фактов: "метод Х выполняется дольше, чем мы хотим".


Вот наблюдение этого факта должно начинается не в продакшене и даже не в момент когда запускаются интеграционные тесты,
а в момент когда разработчик только начинает писать запрос.
Условно у вас есть база с десятком миллионов записей, разработчик написал какой-нибудь join с другой и не видит проблемы.
Заливает это в Git и потом ночные тесты висят несколько часов.

Если он сразу этот запрос начнет писать в клиенте субд и попробует его скомпилировать и выполнить, то сразу обнаружит проблему и пофиксит.
Поэтому я за то чтобы писать SQL и сразу его комилить и отлаживать.

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

S>Затем идёт профилирование, в поисках конкретного узкого места — например, конкретного запроса, который тормозит на конкретных данных.

S>Видите — хинты идут далеко не первыми даже после того, как мы убедились в необходимости оптимизации конкретного запроса.

Видите это не совсем так, зависит от вашего процесса разработки. Минусы отложенного поиска проблем можно перечислять долго.

S>Написание их заранее — верный способ выкопать себе яму, т.к. распределение реальных данных может сильно отличаться от фантазий разработчика. Опытнейшие люди индустрии десятилетиями полируют движки СУБД, чтобы они выбирали оптимальный план для каждого запроса. Хинт связывает руки оптимизатору, так что план, "оптимальный" на тестовых данных, может на порядок хуже исполняться на боевых.


Это действительно так , т.к. важна например статистика,
но хинты они про разное, те которые про статистику их не надо вносить раньше времени, те которые не про статистику, а про кэш данных например те можно.
Но повторюсь что при формировании запроса могут использоваться не только хинты но и другие специфичные операторы, которые рекомендованы к использованию в каких-то кейсах, в каких-то нет.

O>>Ну и в итоге вы берете некий IQueryable который уже как "черный ящик" , накладывате на него еще запросы и скрещиваете пальцы что щас вам linq2db разрулит все сам и даст лучший запрос.

O>>Не понимая какой запрос в итоге получится что на самом деле откинется, а что нет, если будет несколько таких вложенных запросов.
S>Нет, так не получится. Если вы хотите писать эффективно работающие с СУБД приложения, нужно понимать, как работает SQL. Какие запросы должны быть написаны.
S>И вот в таком случае link2db даст вам возможность эффективно писать эффективный SQL.

Верно, поэтому вы должны видеть конечный SQL и с ним работать, а в уме преобразовывать за каждый драйвер базы ваш Linq и представлять в уме как он раскладывается
не говорите мне что у вас это получается. Уверен либо только очень простые, либо вы все таки не представляете в уме какой запрос будет сформирован.

O>>пусть даже там окажется какой-то общий подзапрос, он вполне может оказаться не общим через какое-то время. Так будет намного безопаснее для изменений в будущем.

S> Это тупиковый путь.
А где тупик то ? Очень часто делают ошибку что для разных сущностей пытаются что-то обобщить, а потом это общее ломается.
Все таки предпочитаю взвешивать трудоемкость и общность, если не трудоемко то лучше общее которое может измениться в будущем не считать общим.

S>Не, не то же самое. Link2db писали практики, у которых не было идеи "давайте изолируем разработчика от СУБД". У них была идея "мы хотим писать офигенный SQL, только быстрее и надёжнее, чем в хранимках или репозиториях".

Возможно они хотели, но должны были понимать что expresions как входных данных не достаточно для написания офигенного SQL.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[26]: Архитектура доступа к бд
От: · Великобритания  
Дата: 19.04.19 08:47
Оценка:
Здравствуйте, okon, Вы писали:

O>>>Ну собственно про это и речь, не важно как ее назвать, я ее называю IRepository.

O>>>По сути она и будет предоставлять доступ к данным, а реализация для каждой СУБД своя, или про что хотели сказать ?
O>·>IRepository слишком специфично. "A repository is an abstraction which represents any underlying and arbitrary data store as if it were an in memory collection of objects". Или ты не то так называешь.
O>Не совсем понятно что имелось ввиду "как бы представленно коллекцией в памяти"
Так погугли что называют Repository.

O>я говорю про то что мы описываем интерфейс для доступа к данным,

O>и делаем реализацию специфичную для СУБД.
Это называется DAL. А репозиторий — один из конкретных подходов.

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

O>·>Ага. Вот только слово "если" — тут ключевое. Premature optimisation, слыхал?
O>Она может быть Premature на начальном этапе разработки, к концу разработки или после начала промышленной эксплуатации это становиться уже скорее ежедневной рутиной задачи на оптимизацию.
Или не становится.

O>Т.е. как бы вы не выражали свой SQL через linq2db или другим способом — появится специфика и потребуется разделение реализации для каждой субд, причем еще как правило для версий СУБД.

O>Например в более современных можно использовать новые возможности , которые нельзя делать на старых базах.
Ты правда считаешь, что все over 9000 запросов в типичном приложении надо затачивать под каждую версию субд? По поему опыту, доли процента всех запросов имеют какие-то особенности и требуют допиливания.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[26]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 19.04.19 09:10
Оценка: 74 (2)
Здравствуйте, okon, Вы писали:

S>>
S>>select Document.* from Document inner join Permissions on Document.Id = Permission.RowId and Permission.TableName = 'Document' and UserId = @CurrentUser
S>>where Permissions.CanRead = 1
S>>


S>>Вы не сможете написать на SQL мета-функцию, которая бы возвращала отфильтрованный датасет для любой таблицы.

S>>Либо вы будете писать 2000 TVF вида GetAllowedDocuments, GetAllowedStores, GetAllowedPersons и так далее.
O>А как это вы сделаете на Linq2Sql, тоже напишете же
O>GetDocuments()/GetStores(), а потом будете еще добавлять GetStores().AllowedPermissions() , не так ли ?

[Skip]

Вам действительно инетерсено или вы думаете мы чего-то не понимаем? Я плотно работаю с базами 20 лет, Антон и того больше. Вы думаете мы от хорошей жизни перешли на linq2db (Антон, не link2db).
В linq2db была найдена золотая середина между статической типизацией и голым сиквелом.

Я не пишу больше сиквелы, я читаю что генерит linq2db, и в 99% это идеально. Беру этот сиквел и хоть в статью вставляй.
И это на порядок проще чем писать строки. Перестраивать LINQ Query в разы безопасней чем поправлять SQL. В LINQ я могу разбить запрос на запчасти, проверить каждую из них и с уверенностью клеить дальше — это очень спасает когда вы не можете понять когда произошло декартовое произведение.
Плюсы можно перечислять долго, из минусов — надо выучить LINQ и желательно знать как работает Expression Tree. Это знание мне помогает придумывать всеьма элегантные солюшины.

interface IPermissionAware
{
   int RowId { get; }
}

[Table("Document")]
class Document : IPermissionAware
{
   public int RowId { get; set; }   
   public bool IsDone { get; set; }   
   public bool IsApproved { get; set; }   
   ....
}

[Table("Order")]
class Order : IPermissionAware
{
   public int RowId { get; set; }   
   ....
}

public static class PermissionExtensions
{
   public static IQueryable<T> GetAllowed<T>(this IDataContext db)
     where T: IPermissionAware
   {
      var ed = db.MappingSchema.GetEntityDescriptor(typeof(T));
      var query = from t in db.GetTable<T>()
                  from p in db.GetTable<Permissions>().InnerJoin(p => p.TableName = ed.TableName && p.RowId == t.RowId)
                  select t;
      return query;
   }
}

Ну и понеслась
using (var db = new DataConnection())
{
   // взять только количество
   var count = db.GetAllowed<Document>().Count();

   // отфильтровать еще раз и проставить значение
   db.GetAllowed<Document>()
     .Where(d => d.IsDone)
     .Set(d => d.Approved, true)
     .Update();

   // вставить в другую таблицу
   db.GetAllowed<Document>().Into(db.GetTable<ArchiveDocument>())

   // снести их с базы к черту
   db.GetAllowed<Document>().Delete();
}

Я тут ни строчки SQL не написал, зато заменил одним универсальным методом с десяток методов репозитория да и CRUD прикрутил.
Re[20]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 19.04.19 09:21
Оценка:
Здравствуйте, okon, Вы писали:

[Skip]

O>Оцениваю то что он может, то что и его постоянно надо контролировать и всякими гвоздями потом прибивать если он что-то делает неправильно,

O>вместо того чтобы спокойно писать чистый SQL который нужно получить в итоге.

Вот найдете багу, пишите на github — я это дело быстро починю.
А так это пустые слова. Ничего гвоздями не прибивал уже очень давно и строил настолько трехэтажные сиквелы что только в страшном сне привидится.
Re[27]: Архитектура доступа к бд
От: okon  
Дата: 19.04.19 09:57
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, okon, Вы писали:


O>>Не совсем понятно что имелось ввиду "как бы представленно коллекцией в памяти"

·>Так погугли что называют Repository.
·>Это называется DAL. А репозиторий — один из конкретных подходов.

ранее не гуглил, но в разных книгах и курсах видел примеры где используется термин IRepository для абстракции работы с данными ( без загрузки в память и кэширования ).


O>>Она может быть Premature на начальном этапе разработки, к концу разработки или после начала промышленной эксплуатации это становиться уже скорее ежедневной рутиной задачи на оптимизацию.

·>Или не становится.
Как я пояснял уже что начальная "оптимизация" возникает уже при первом запуске запроса когда вы его начинаете писать.
Вы убираете оттуда не нужное, используете известные рекомендуемые практики для конкретной СУБД, если это не вредит делу.


O>>Т.е. как бы вы не выражали свой SQL через linq2db или другим способом — появится специфика и потребуется разделение реализации для каждой субд, причем еще как правило для версий СУБД.

O>>Например в более современных можно использовать новые возможности , которые нельзя делать на старых базах.
·>Ты правда считаешь, что все over 9000 запросов в типичном приложении надо затачивать под каждую версию субд? По поему опыту, доли процента всех запросов имеют какие-то особенности и требуют допиливания.

Не обязательно все , но требуется возможность
— сделать часть запросов для специфичной версии
— не поломать работу других версий

Поэтому в любом случае появляется абстакция в виде интерфейса и специфика в видее реализации этого интерфейса и без нее будет сложно поддерживать оптимальную работу разных версий.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[21]: Архитектура доступа к бд
От: okon  
Дата: 19.04.19 11:35
Оценка:
O>>Оцениваю то что он может, то что и его постоянно надо контролировать и всякими гвоздями потом прибивать если он что-то делает неправильно,
O>>вместо того чтобы спокойно писать чистый SQL который нужно получить в итоге.

D>Вот найдете багу, пишите на github — я это дело быстро починю.

D>А так это пустые слова. Ничего гвоздями не прибивал уже очень давно и строил настолько трехэтажные сиквелы что только в страшном сне привидится.


вам нужно выбрать имена всех гномиков у которых рост > 1m, в базе рост хранится в строковом виде,
где-то просто число, где-то в виде типа 0,25m или 0.5m или 1m. при этом множество вариантов ограничено и других не бывает,
например 0,25m, 0.5m, 0.75m, 1m, 1.5m

Как вы запишете эти условия в Linq2db и какой конечный запрос сгененрится ?
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[22]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 19.04.19 12:23
Оценка:
Здравствуйте, okon, Вы писали:

O>>>Оцениваю то что он может, то что и его постоянно надо контролировать и всякими гвоздями потом прибивать если он что-то делает неправильно,

O>>>вместо того чтобы спокойно писать чистый SQL который нужно получить в итоге.

D>>Вот найдете багу, пишите на github — я это дело быстро починю.

D>>А так это пустые слова. Ничего гвоздями не прибивал уже очень давно и строил настолько трехэтажные сиквелы что только в страшном сне привидится.


O>вам нужно выбрать имена всех гномиков у которых рост > 1m, в базе рост хранится в строковом виде,

O>где-то просто число, где-то в виде типа 0,25m или 0.5m или 1m. при этом множество вариантов ограничено и других не бывает,
O>например 0,25m, 0.5m, 0.75m, 1m, 1.5m

O>Как вы запишете эти условия в Linq2db и какой конечный запрос сгененрится ?


Напишите мне SQL и я вам дам результат. Если надо UDF — то он подключается с полпинка.
Re[23]: Архитектура доступа к бд
От: okon  
Дата: 19.04.19 23:47
Оценка: -1
O>>вам нужно выбрать имена всех гномиков у которых рост > 1m, в базе рост хранится в строковом виде,
O>>где-то просто число, где-то в виде типа 0,25m или 0.5m или 1m. при этом множество вариантов ограничено и других не бывает,
O>>например 0,25m, 0.5m, 0.75m, 1m, 1.5m

O>>Как вы запишете эти условия в Linq2db и какой конечный запрос сгененрится ?


D>Напишите мне SQL и я вам дам результат. Если надо UDF — то он подключается с полпинка.


Я конечно тут сделал "лазейку" что можно просто сравнить > '1', но хотелось немного сложнее, пусть будет > '0.75'

Допустим я пишу запрос и хочу попробовать несколько вариантов , т.к. сомневаюсь в том какой вариант будет лучше.

— через Decode
— через Case
— через To_Number
— Deterministic функцию

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

Собственно можно ли этот "баг" пофиксить, чтобы я также писал сразу Linq2Sql выражение как я это делаю в SQL ?
Вопрос мне видится как риторический с ответом на него — нет.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 19.04.2019 23:51 okon . Предыдущая версия .
Re[22]: Архитектура доступа к бд
От: Mystic Artifact  
Дата: 20.04.19 01:01
Оценка:
Здравствуйте, okon, Вы писали:

O>вам нужно выбрать имена всех гномиков у которых рост > 1m, в базе рост хранится в строковом виде,

O>где-то просто число, где-то в виде типа 0,25m или 0.5m или 1m. при этом множество вариантов ограничено и других не бывает,
O>например 0,25m, 0.5m, 0.75m, 1m, 1.5m
O>Как вы запишете эти условия в Linq2db и какой конечный запрос сгененрится ?
Извиняюсь, но это не *база* *данных* — это самая обычная мусорка. К мусоркам пишут запросы на SQL, JS, и чем угодно: адаптивное построение плана запроса в сиквеле к примеру давно есть, и внедрено по тихому, в то время как некоторые это умудрялись выпичивать чуть ли не как киллер фичу. Тьфу. Есть эффективные способы работы с *мусором*, но лучше, при первой возможности, править в консерватории, а не городить костыли.

Я работаю регулярно с костылями которым лет 20. С новыми веяниями, тут EFC в моде — это вапще жесть иногда выходит. А причина того — не легаси код, не чужие баги в голове.

Причина — *непонимание задачи*.

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

Так и вы тут...
Re[23]: Архитектура доступа к бд
От: okon  
Дата: 20.04.19 01:08
Оценка:
Здравствуйте, Mystic Artifact, Вы писали:

MA>Здравствуйте, okon, Вы писали:


O>>вам нужно выбрать имена всех гномиков у которых рост > 1m, в базе рост хранится в строковом виде,

O>>где-то просто число, где-то в виде типа 0,25m или 0.5m или 1m. при этом множество вариантов ограничено и других не бывает,
O>>например 0,25m, 0.5m, 0.75m, 1m, 1.5m
O>>Как вы запишете эти условия в Linq2db и какой конечный запрос сгененрится ?
MA> Извиняюсь, но это не *база* *данных* — это самая обычная мусорка. К мусоркам пишут запросы на SQL, JS, и чем угодно: адаптивное построение плана запроса в сиквеле к примеру давно есть, и внедрено по тихому, в то время как некоторые это умудрялись выпичивать чуть ли не как киллер фичу. Тьфу. Есть эффективные способы работы с *мусором*, но лучше, при первой возможности, править в консерватории, а не городить костыли.

Согласен что мусорка, но с такими легаси мусорками встречаться приходится на практике достаточно часто и не всегда можно поправить консерваторию — быстро сделать рефакторинг базы, т.к. там еще 100 500 хранимых процедур в логике которых замешано использование в таком формате и ничего не поделать, нужно как-то делать приемлемое решение, т.е. городить именно что костыль.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[24]: Архитектура доступа к бд
От: Mystic Artifact  
Дата: 20.04.19 01:19
Оценка: +1
Здравствуйте, okon, Вы писали:

O>Согласен что мусорка, но с такими легаси мусорками встречаться приходится на практике достаточно часто и не всегда можно поправить консерваторию — быстро сделать рефакторинг базы, т.к. там еще 100 500 хранимых процедур в логике которых замешано использование в таком формате и ничего не поделать, нужно как-то делать приемлемое решение, т.е. городить именно что костыль.


Тогда я вообще не понимаю: работая с такого рода предикатами ты в сущности всегда упрешься вперебор по полю. Плюс linq2db, что ты имеешь три опции:

1) встроенное выражение, навроде getdate() которое превращается в родной SQL без параметра как есть
2) выражаем через переменную — получаем константу в *параметризованном* запросе
3) вариант (2) но используем инлайновые константы

2/3 — это ахрененно важный выбор, т.к. перекосы в индексах есть, а от них зависят планы, а тут периодика которая долбит сиквел тем самым провоцируя кешировать совсем не то, что мы хотим.

Я скажу так: идеален ли linq2db — вовсе нет. Можно ли с ним работать? Нужно. Это лучшее решение для доступа в БД в этом духе. Оно просто тебя не ограничивает сверху, например, как EF(C).

А универсальность — это обычно призрак. Т.е. универсальные приложения могут существовать, но с примитивными БД. В промышленных случаях, всегда надо идти на компромисс. Например для генерируемых данных — выделить отдельную БД в simple. Там специфики в каждой БД слишком дохрена. Просто, в 95% оно не нужно. Но в остальных 5% — не нужно упираться и отказываться от хинтов или еще чего-то такого.

ADD: подразумеваются генерируемые и восстановимые данные из вышележащих.
Отредактировано 20.04.2019 1:22 Mystic Artifact . Предыдущая версия .
Re[24]: Архитектура доступа к бд
От: Mystic Artifact  
Дата: 20.04.19 01:44
Оценка:
Здравствуйте, okon, Вы писали:

Тут есть еще одна деталь, но это вообще оффтопик, и просто к слову.

У нас есть генератор запросов (текстовый), и вот он генерирует ахинею, там куча ошибок логических, навроде того, что фильтр даты есть, но выбирается по вьюхе без возможности ограничить выбираемые строки (даты в своем формате — вычислимое поле = полный скан). Так вот, переписывание этого на использование фильтра по дате не дает ничего. Просто ничего. Что мой домашний комп, что *боевой* сервер способен их перебрать очень и очень быстро, при этом, это мешает применить иные индексы. Но, парадокс в том, что на девелоперском сервере — это работает из рук вон плохо, а фильтр по дате таки серьезно (на порядок) уменьшает число чтений.

Так вот, пофигу тут, рукописный или linq заппос абсолютно. А вы попробуйте сгруппировать 53 поля over 10M записей.

Ну и да — легаси и данность. Я борюсь за оптимизацию, прежде всего логическую: люди всегда добавляли колонки банально нулабельные и тому подобное. Мрак полный. Херова туча инсталляций с какими-то автоиндексами (уникальными/разными).

DBA фактически нет, но индексы сами бы не появились. Кто-то натравил тулзу же. Железо выделенное и мощное (через чур, о таком мы тока мечтали ранее.)

Ты тут видишь хоть намек на универсальность?
Re[24]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 20.04.19 06:40
Оценка: +1
Здравствуйте, okon, Вы писали:

O>>>вам нужно выбрать имена всех гномиков у которых рост > 1m, в базе рост хранится в строковом виде,

O>>>где-то просто число, где-то в виде типа 0,25m или 0.5m или 1m. при этом множество вариантов ограничено и других не бывает,
O>>>например 0,25m, 0.5m, 0.75m, 1m, 1.5m

O>>>Как вы запишете эти условия в Linq2db и какой конечный запрос сгененрится ?


D>>Напишите мне SQL и я вам дам результат. Если надо UDF — то он подключается с полпинка.


O>Я конечно тут сделал "лазейку" что можно просто сравнить > '1', но хотелось немного сложнее, пусть будет > '0.75'


O>Допустим я пишу запрос и хочу попробовать несколько вариантов , т.к. сомневаюсь в том какой вариант будет лучше.


O>- через Decode

O>- через Case
O>- через To_Number
O>- Deterministic функцию

O>На SQL я быстро могу попробовать эти варианты.

O>Т.е. сначала я напишу их на SQL,
O>попробую и вместо того чтобы просто взять понравившийся вариант, я должен его потом еще перевести на Linq2Sql — дополнительная работа,
O>потом еще позаботится чтобы на других базах оно также работало

O>Собственно можно ли этот "баг" пофиксить, чтобы я также писал сразу Linq2Sql выражение как я это делаю в SQL ?

O>Вопрос мне видится как риторический с ответом на него — нет.

Вы привели пример самый что ни на есть SQL-ый. Тут вам никто не поможет, вы даже базу менять не будете, так как она уже не оптимальна и репозитории тут также к черту. И все равно, вы сможете написать функцию фильтра, который с полпинка подменяется для другой базы, и вам хватит только ее переписать или просто сделать в стиле DI.

public interface IDwarfFilter
{
    IQueryable<Dwarf> FilterByHeight(IQueryable<Dwarf> source, double height);
}


Вот и все, дальше с этим IQueryable также делайте что хотите, переиспользуя во всех запросах.

Время от времени появляются такие запросы, но ооочень редко, опять же из-за этого я не буду городить репозитроий никогда.
Re[13]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 23.04.19 15:44
Оценка:
Здравствуйте, Danchik, Вы писали:

O>>А как там оракловые хинты к запросу указать ?

D>Ну что же, попал.

Почти попал. На Sql.Expression можно любую фигню нагенерировать.
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 23.04.19 15:59
Оценка:
Здравствуйте, okon, Вы писали:

O>А какая СУБД ? Размеры таблиц ?


За всю Одессу не скажу. У меня на проекте база на сегодняшний день ~5.5 TB реляционных данных. Количество записей ~175 мильярдов. Ежедневно генерируется порядка 10GB данных/200M записей. Таблиц 4-5 сотен. Ни одной строчки не написано на SQL. Всё исключительно на linq2db. Проблемы производительности в linq2db не упираются никаким боком. Это либо проблемы дизайна, либо оптимизации запросов.
Если нам не помогут, то мы тоже никого не пощадим.
Re[20]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 23.04.19 16:08
Оценка:
Здравствуйте, okon, Вы писали:

O>вот кстати местный форумчанин также описал проблемы о которых я говорю.

O>https://habr.com/ru/post/230479/

Эти проблемы ни к linq вообще, ни к linq2db в частности не имеют никакого отношения.
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: Архитектура доступа к бд
От: okon  
Дата: 23.04.19 16:25
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, okon, Вы писали:


O>>А какая СУБД ? Размеры таблиц ?


IT>За всю Одессу не скажу. У меня на проекте база на сегодняшний день ~5.5 TB реляционных данных. Количество записей ~175 мильярдов. Ежедневно генерируется порядка 10GB данных/200M записей. Таблиц 4-5 сотен. Ни одной строчки не написано на SQL. Всё исключительно на linq2db. Проблемы производительности в linq2db не упираются никаким боком. Это либо проблемы дизайна, либо оптимизации запросов.


Да, нормальная база, а из какой предметной области ?
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[26]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 23.04.19 16:46
Оценка:
Здравствуйте, okon, Вы писали:

O>Верно, поэтому вы должны видеть конечный SQL и с ним работать, а в уме преобразовывать за каждый драйвер базы ваш Linq и представлять в уме как он раскладывается

O>не говорите мне что у вас это получается. Уверен либо только очень простые, либо вы все таки не представляете в уме какой запрос будет сформирован.

Конечный SQL всегда с нами. В логе или в окне отладке. Хорошо отформатированный, с подставленными параметрами, готовый к переносу и употреблению в SSMS.
Если нам не помогут, то мы тоже никого не пощадим.
Re[24]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 23.04.19 16:51
Оценка:
Здравствуйте, okon, Вы писали:

O>Собственно можно ли этот "баг" пофиксить, чтобы я также писал сразу Linq2Sql выражение как я это делаю в SQL ?

O>Вопрос мне видится как риторический с ответом на него — нет.

Да — https://www.linqpad.net/
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 23.04.19 16:57
Оценка: 2 (1)
Здравствуйте, okon, Вы писали:

O>Да, нормальная база, а из какой предметной области ?


Ценные бумажки.
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: Архитектура доступа к бд
От: MadHuman Россия  
Дата: 23.04.19 17:05
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, okon, Вы писали:


O>>Да, нормальная база, а из какой предметной области ?


IT>Ценные бумажки.

ну раз такая пьянка, а какая СУБД ? ...
сколько одновременных юзеров?
ну и чтоб два раза не вставать, на каком железе?) и если не сильно затруднит поделитесь опытом, как оно все росло, как эволюционировала архитектура приложения) ?)

Заранее спасибо!
Отредактировано 23.04.2019 17:12 MadHuman . Предыдущая версия .
Re[10]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 23.04.19 18:12
Оценка: 78 (4)
Здравствуйте, MadHuman, Вы писали:

IT>>Ценные бумажки.

MH>ну раз такая пьянка, а какая СУБД ? ...

Сначала была морда на ASP.NET, процессинг на коболе AS/400 и соответственно DB2 z/OS в качестве БД (благодаря этому в linq2db появилась поддержка z/OS, а то где бы ещё взять такую экзотику).
Сейчас процессинг переписан на .NET, база — MS SQL.

MH>сколько одновременных юзеров?


Юзеров у нас не много. Это внутренний банковский софт для агрегации и анализа ценных бумажек. Ну несколько десятков, размазанных по всем часовым поясам.

MH>ну и чтоб два раза не вставать, на каком железе?) и если не сильно затруднит поделитесь опытом, как оно все росло, как эволюционировала архитектура приложения) ?)


Железо хорошее По крайней мере сейчас. Хотя по началу нас засунули на виртуалки. Росло всё тоже хорошо, за исключением пожалуй одного момента. Когда база начала наполнятся реальными данными, то стала наблюдатся неприятная и устойчивая деградация производительности. Срочно пришлось прикручивать партишининг. Но так как до этого всё дизайнилось с понимаем, что это рано или поздно придётся делать, то всё прошло благополучно и почти прозрачно.

Кстати, переход с DB2 на MSSQL прошёл легко как по маслу во многом благодаря linq2db.

В общем, я не вижу проблем с linq2db. Отчасти, естественно, потому что сам имею непосредственный доступ к телу и все нужные расширения зачастую сначала делаются и обкатываются на практике, а уже потом унифицируются и добавляются в библиотеку. Но и других объективных проблем не вижу. Зато плюсов вижу много. В первую очередь — полностью типизированный код всего приложения со всеми последствиями. Показанные уже Синклером техники использования повторного кода. Широкомасштабное использование метапрограммирования. Те методы (точнее похожие на), которые демонстрировал Sinclair, мы руками не пишем, мы их генерируем. Соответственно, если в таблице появляется, например, пара полей EffectiveDate/ExpirationDate, то для неё сразу при генерации модели данных генерируется ещё и пачка сопутствующих методов, а на саму таблицу накладываются дополнительные интерфейсы. Наш T4 для генерации модели размером примерно в 1500 строк. Можно представить чем он там занимается.
Если нам не помогут, то мы тоже никого не пощадим.
Re[25]: Архитектура доступа к бд
От: okon  
Дата: 24.04.19 04:50
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, okon, Вы писали:


O>>Собственно можно ли этот "баг" пофиксить, чтобы я также писал сразу Linq2Sql выражение как я это делаю в SQL ?

O>>Вопрос мне видится как риторический с ответом на него — нет.

IT>Да — https://www.linqpad.net/


Почти, но вот наприсал я первый запрос смотрю что-то долго выполняется, решил попробовать хинт или какой-то специфичный оператор decode например.
Сразу возникает 2 момента
— а есть ли в linq2db его реализация, т.е. что конкретно мне надо напечатать чтобы получить нужный результат
— оказалось что нет, так а как дальше, надо написать extension метод

т.е. работая с SQL я сразу напишу то что я хочу, это намного быстрее получается.

У Linq2Db я вижу плюс в том что да я могу динамические запросы делать более безопасно и на простых запросах это будет с большой вероятностью оправдано.
Удасться ли придерживаться простых запросов чтобы не сталкиваться с кейсом который я описал выше, на моей практике нет,
но я работал в основном с большими legacy базами.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[9]: Архитектура доступа к бд
От: okon  
Дата: 24.04.19 05:15
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, okon, Вы писали:


O>>Да, нормальная база, а из какой предметной области ?

IT>Ценные бумажки.

Было бы интересно узнать с какими проблемами оптимизации пришлось столкнуться и каким образом их решали.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[11]: Архитектура доступа к бд
От: MadHuman Россия  
Дата: 24.04.19 07:28
Оценка:
Здравствуйте, IT, Вы писали:

IT>Юзеров у нас не много. Это внутренний банковский софт для агрегации и анализа ценных бумажек. Ну несколько десятков, размазанных по всем часовым поясам.

видимо у вас в основном OLAP нагрузка? несчитая ежедневной доливки данных..


IT>Железо хорошее

это понятно интересно 5ТБ база живёт на одном сервере?
MS SQL насколько я помню не умеет легко масштабироваться горизонтально. даже это проблема не MS SQL-я а реляционных баз в принципе (ибо джойны, транзакции).
если на одном, то сколько там памяти? 5ТБ?
если меньше (хотя зачем, если сейчас можно на сервер и 5ТБ поставить), то видимо приходится запросы жестко тюнить чтоб оперируемый ими объём в ОЗУ вмещался?...

IT>Когда база начала наполнятся реальными данными, то стала наблюдатся неприятная и устойчивая деградация производительности. Срочно пришлось прикручивать партишининг

партишинг же накладывает довольно жесткие ограничения на запросы к бд.. в частности в запросе должен присутствовать критерий выборки по ключу партишинга (например интервал дат).
и если сценарий (репорт) требуют использования всех данных, то партишинг не поможет.. тут обычно переходят на что-то горизонтально масштабируемое (всякие NoSql).. как у вас было?
нет таких сценариев ?
Отредактировано 24.04.2019 7:36 MadHuman . Предыдущая версия .
Re[12]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 24.04.19 07:53
Оценка:
Здравствуйте, MadHuman, Вы писали:


MH>MS SQL насколько я помню не умеет легко масштабироваться горизонтально. даже это проблема не MS SQL-я а реляционных баз в принципе (ибо джойны, транзакции).


Тут уже начинают удивлять, редко но появляются: https://pingcap.com/en/
Re[13]: Архитектура доступа к бд
От: MadHuman Россия  
Дата: 24.04.19 08:02
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, MadHuman, Вы писали:



MH>>MS SQL насколько я помню не умеет легко масштабироваться горизонтально. даже это проблема не MS SQL-я а реляционных баз в принципе (ибо джойны, транзакции).


D>Тут уже начинают удивлять, редко но появляются: https://pingcap.com/en/

дак принципиальные то ограничения никуда не денутся... а именно — джойны, когда данные которые джойнить на разных нодах..
и когда транзакция затрагивает данные разных нодов, но нужен не "в конечном счете", а вот нормальная транзакция "все или ничего".
по ссылке не вникал ибо против фундаментала не попреш)
Re[26]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 24.04.19 13:54
Оценка: +1
Здравствуйте, okon, Вы писали:

O> — а есть ли в linq2db его реализация, т.е. что конкретно мне надо напечатать чтобы получить нужный результат

O> — оказалось что нет, так а как дальше, надо написать extension метод

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

O>т.е. работая с SQL я сразу напишу то что я хочу, это намного быстрее получается.


Наклепать по быстрому запрос и у меня получается бытсрее на SQL. Речь не о том. Речь идёт о коде, который потом едет в продакшин. О том, что ты потом годами будешь поддерживать, развивать и рефакторить.

O>У Linq2Db я вижу плюс в том что да я могу динамические запросы делать более безопасно и на простых запросах это будет с большой вероятностью оправдано.


Ты даже не представляешь размеры наших запросов. Умельцы лепят до полусотни джоинов, руки поотбивалбы. Одно спасение — linq2db умеет отсекать неиспользуемые left joins.

O>Удасться ли придерживаться простых запросов чтобы не сталкиваться с кейсом который я описал выше, на моей практике нет,

O>но я работал в основном с большими legacy базами.

Мы все работали с большими легаси базами и у нас у все богатая практика использования большой совковой лопаты по перекладыванию из одной кучи в другую. Как я уже сказал, конкретно для твоего случая может чего-то и не реализовано, но это всё легко исправляется.
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 24.04.19 14:08
Оценка: 123 (2)
Здравствуйте, okon, Вы писали:

O>Было бы интересно узнать с какими проблемами оптимизации пришлось столкнуться и каким образом их решали.


Sinclair их все уже описал, за исключением пожалуй одного случая. Иногда у оптимизатора сносит крышу и он никак не хочет строить оптимальный запрос. Ну вот хоть ты его стреляй. Ни хинты, ни статистика, ни option(recompile), ничего. Обычно это происходит на таблицах размером в 200M+ записей. Тогда приходится ему помогать, разбивать запрос на запчасти и выполнять его через частями через временные таблицы. Выглядит это примерно так:

using (var tmp = db.CreateTempTable("#tmp", from t in Table ..... select new { ... })
{
    from t1 in db.MyTable
    join t2 in tmp on ....
}


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

Если надо данные во временную таблицу можно закачать с клиента

using (var tmp = db.CreateTempTable("#tmp", myList)
{
    from t1 in db.MyTable
    join t2 in tmp on ....
}


В этом случае будет использоваться BulkCopy, чего в ручную почти никто и никогда не делает. Т.е мой код на линке по производительности с гарантией сделает любой другой рукописный код на SQL.
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: Архитектура доступа к бд
От: IT Россия linq2db.com
Дата: 24.04.19 14:17
Оценка:
Здравствуйте, MadHuman, Вы писали:

MH>видимо у вас в основном OLAP нагрузка? несчитая ежедневной доливки данных..


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

MH>если на одном, то сколько там памяти? 5ТБ?

MH>если меньше (хотя зачем, если сейчас можно на сервер и 5ТБ поставить), то видимо приходится запросы жестко тюнить чтоб оперируемый ими объём в ОЗУ вмещался?...

Глянул. PRIMARY на 6 SSD дисках по 1-2 TB. Ещё три диска с какими-то ndf.

MH>партишинг же накладывает довольно жесткие ограничения на запросы к бд.. в частности в запросе должен присутствовать критерий выборки по ключу партишинга (например интервал дат).


Обязательно и неприменно. Более того, если две таблицы джоинятся по этим полям, то всё равно для обоих необходимо указывать фильтр в WHERE.

MH>и если сценарий (репорт) требуют использования всех данных, то партишинг не поможет.. тут обычно переходят на что-то горизонтально масштабируемое (всякие NoSql).. как у вас было?

MH>нет таких сценариев ?

Только во всяких maintenance jobs. В остальных случаях удаётся избегать. Но мы под это дело изначально базу дизайнили.
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 24.04.19 16:47
Оценка:
Здравствуйте, MadHuman, Вы писали:

MH>Здравствуйте, Danchik, Вы писали:


D>>Здравствуйте, MadHuman, Вы писали:



MH>>>MS SQL насколько я помню не умеет легко масштабироваться горизонтально. даже это проблема не MS SQL-я а реляционных баз в принципе (ибо джойны, транзакции).


D>>Тут уже начинают удивлять, редко но появляются: https://pingcap.com/en/

MH>дак принципиальные то ограничения никуда не денутся... а именно — джойны, когда данные которые джойнить на разных нодах..
MH>и когда транзакция затрагивает данные разных нодов, но нужен не "в конечном счете", а вот нормальная транзакция "все или ничего".
MH>по ссылке не вникал ибо против фундаментала не попреш)

Пишут что поддерживают джоины. Транзакции тоже (optimistic)
Re[20]: Архитектура доступа к бд
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.05.19 08:25
Оценка: 24 (1)
Здравствуйте, okon, Вы писали:
O>GetNewId это совсем не про то как нужно делать реализацию, а про то что есть специфика у разных СУБД которую требуется описать специальным образом.
Обычно этой специфики — пять копеек. Репозиторий — это крайне тяжёлое решение данной задачи.
В итоге вы получите 10+ XXXRepository, у которых 99% кода — бойлерплейт. При этом этот бойлерплейт всё равно надо холить и лелеять — каждый раз, как появляется минимальная особенность вроде нового поля или нового ентити, нужно бежать с коммитом во все эти репозитории.
Вы, конечно же, постараетесь всё исправить — ну, там, репозитории же тоже можно наследовать друг от друга. Давайте сделаем MSSQL2012Repository: MSSQLRepository.
Увы — SQL устроен не так; между новым Oracle и новым MSSQL меньше отличий, чем между ними же старых версий.
В итоге,вменяемого графа наследования репозиториев друг от друга не получится.

O>Но логика не заключается только во вставке с идентити, а если мне нужно сначала вычислить Indentity ? потом показать его в интерфейсе, отчете, и только потом вставить значение с этим идентити.

Если — то да, сделаете функцию резервирования идентити. При этом у вас на все 20-30 версий различных СУБД будет 2 или 3 реализации.
Заводить ради этого целую кунсткамеру репозиториев крайне невыгодно.

O>Поддержка от производителя само собой. А что именно делает софт ?

Автоматизирует бизнес сервис провайдеров. Все вот эти вот "виртуальный сервер за 5 долларов", "cloud mail", и всё-всё-всё что продают эти ребята в интернете.
Какой срок по устранению дефектов стоит в договоре ?
Никакого. Сейлза, который подпишет контракт с фиксированным сроком устранения "дефектов", анально расстреляют за профнепригодность. Взрослые люди понимают, что не бывает ни бездефектного софта, ни возможности за конечное время починить произвольный дефект. Тем более, что нет никакого объективного способа отличить баг от фиче-реквеста.

O>Например приходят сотрудники на работу, запускают программу и видят ошибку на экране, вы находитесь в другой часовой зоне — в какой срок по договору вы должны устранить дефект и выдать рабочую версию ?

По договору, мы должны ответить на заявку в течение оговорённого срока. Работают над заявками, как и в любой взрослой компании, специально обученные люди, по графику 24/7.
В жизни ситуаций типа "приходят сотрудники на работу, запускают программу и видят ошибку на экране", вызванных именно программными багами, не бывает. Вчера же не было этой ошибки?
Значит, кто-то что-то подкрутил на инсталляции партнёра — и саппорт оперативно разбирается в причинах проблемы. Статистика примерно такая:
90%: никакой ошибки нет, это просто новый сотрудник (или старый после отпуска) забыл, как работает система, и тупит. Вариант: софт работает так, как задумано и задокументировано, но партнёр хочет, чтобы он работал ещё лучше.
7%: ошибка есть, является результатом сбоя в каком-то сервисе (сдох винт, кончилось место, отключилось питание, етк))
2%: ошибка есть, является результатом шаловливых ручек админов партнёра, которые решили "а давайте вот так" — например, подкрутили файрволл.
0.9%: сбой не в нашем сервисе, а в сервисе стороннего поставщика (Microsoft накатили апдейт без обратной совместимости на свои сервера)
0.1%: сбой в нашем коде, вызванный накатом обновления, которое мы не протестировали в сценарии конкретного партнёра.
Даже классификация проблемы по этому списку типов может занять несколько дней. Затем идёт согласование сроков починки.
Никто не будет бросать всё и тратить десятки тысяч $$$ на то, чтобы спешно выкатить релиз, чинящий мелкое неудобство.
Есть регулярное расписание maintenance releases. Если бага подтверждена, и починка её недорога, то фикс включат в следующий релиз (как правило, ежемесячный).
O>Как решаются всякие оперативные задачи по обслуживанию базы — переустановки, бэкапы, восстановление, профилактика ?
Бэкапы делаются автоматически, по расписанию, которое настраивается при передаче системы в эксплуатацию.
Всяке переустановки (это вообще что?) делаются за отдельные деньги службой Professional Services. Если заказчик хочет сэкономить, то сажает свою команду. Либо покупает услуги сопровождения у наших партнёров (например, Datacom).
Восстановление из бэкапа означает, как правило, форс-мажор, происходит при участии службы поддержки, и на моей памяти (за 12 лет) происходило считанные разы.

O>Но коллега где-то тут уже приводил рассказ "чуда" что они берут функцию которая возвращает IQueryable , потом навешивают на нее еще логику, еще логику и т.д.

O>и потом получают чудо в виде красивого запроса. Но я же понимаю что это не так. Колелега либо вводит намеряно в заблуждение либо сам заблуждается,
O>может и я заблуждаюсь, но поясню почему я уверен скорее в первых двух — z понимаю же что IQueryable все что может рассказать о запросе это только expression tree и
O>даже человеку не достаточно этих данных чтобы написать правильный запрос.
O>По вашему опыту какие данные входные данные нужны для постановки задачи чтобы написать правильный запрос к субд ?
Минимальные метаданные о структуре таблиц, плюс знания об особенностях конкретного движка СУБД. Ну, чтобы не лепить connect by там, где надо CTE, и не заменять window functions вычислениями на клиенте.
Современные движки в подавляющем большинстве случаев вполне способны прожевать семантически корректные запросы.
Ситуации, когда есть разница между, скажем, вложенным запросом и join, стремительно уходят в прошлое. Даже MySQL, который всю жизнь был тем самым младшим сыном, который "вовсе был дурак", и тот уже вполне прилично оптимизирует запросы без посторонней помощи.

O>Не совсем если ты хорошо знаешь SQL например специфику для Oracle, то для использования всего этого тебе будет очень не удобно, особенно первое время.

O>Когда хочешь написать хинт, а функции нет, когда хочешь вызвать функцию а ее нет либо в явном виде , либо совсем и надо писать extension.
O>Поэтому не получится просто сесть и начать писать если ты писал хорошо и на SQL Oracle и на Linq.
Во-первых, это хорошо. Про нестерпимый зуд "написать хинт" я уже отвечал — для начала, помажьте фенистилом. Если не пройдёт, то можно будет задуматься о более сильнодействующих средствах.
С функциями — почти так же: если у вас многоплатформенность стоит в ultimate goal, то надо думать не только о функциях Oracle, но и о том, как это будет работать на других СУБД.
Внезапно может потребоваться пересмотреть структуру базы так, чтобы приложение приемлемо работало на всём спектре. Или, к примеру, покрыть нужные фичи при помощи UDF. Иначе есть риск наколбасить в OracleRepository vendor-locked код, а что делать на остальных движках — пусть разбирается команда.

O>Ну мой вариант обозначен в моем первом ответе автору топика — http://rsdn.org/forum/dotnet/7421994.1
Автор: okon
Дата: 17.04.19

O>Вы с ним не согласны или просто призываете к написанию SQL на Linq2Sql ?
Ну ужасный же вариант, не так ли? Вы там просто троеточиями обозначили килобайты совершенно одинакового кода, как будто его нет. А в жизни весь этот код нужно написать, отладить, и поддерживать.
Вы попробуйте сесть и по-честному написать обсуждаемые примеры без троеточий. Обратите внимание — коллега Danchik пишет полные решения, которые компилируются и работают. А вы только очерчиваете этаким лёгким движением: "вот здесь у нас будет 15000 loc отборного кода на PL/SQL, написанного высококлассными специалистами в Oracle и в OOAD". "А вот тут — ещё 15000 loc не менее отборного кода, написанного высококлассными специалистами по T-SQL. С хинтами и уникальными функциями".

O>См. выше я описал типичное вхождение в Linq2Sql на практике.

Не вижу.

O>как уже рассмотрели выше — на основании каких входных данных ? считаете ли вы достаточным этих данных для качественного написания запроса ?

Практика показывает, что да.

O>т.к. задачу можно решить разными способами, а наиболее правильный способ зависит от факторов которые в expression не фигурируют.

Например?

O>Вот об этом и речь, а знания нужны не только о Foreign Key и индексах чтобы построить правильный запрос.

Например?

O>Оцениваю то что он может, то что и его постоянно надо контролировать и всякими гвоздями потом прибивать если он что-то делает неправильно,

O>вместо того чтобы спокойно писать чистый SQL который нужно получить в итоге.
Ещё раз: это иллюзия, основанная на заблуждениях. В начале карьеры — да, придётся внимательно смотреть на порождаемый SQL. Потом, попривыкнете к инструменту — станет значительно легче.
Ну, вот вы когда SQL пишете — вы всегда проверяете планы запросов? Или в уме сразу строите примерный план, и только в сложных случаях смотрите, какой из индексов реально подхватился?
А ведь SQL — он гораздо менее жёсткий, чем linq2db. Дистанция между запросами в expression tree и в SQL гораздо меньше, чем между SQL и планом его выполнения.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Архитектура доступа к бд
От: okon  
Дата: 06.05.19 09:13
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, okon, Вы писали:

O>>GetNewId это совсем не про то как нужно делать реализацию, а про то что есть специфика у разных СУБД которую требуется описать специальным образом.
S>Обычно этой специфики — пять копеек. Репозиторий — это крайне тяжёлое решение данной задачи.
S>В итоге вы получите 10+ XXXRepository, у которых 99% кода — бойлерплейт. При этом этот бойлерплейт всё равно надо холить и лелеять — каждый раз, как появляется минимальная особенность вроде нового поля или нового ентити, нужно бежать с коммитом во все эти репозитории.
S>Вы, конечно же, постараетесь всё исправить — ну, там, репозитории же тоже можно наследовать друг от друга. Давайте сделаем MSSQL2012Repository: MSSQLRepository.
O>>Но логика не заключается только во вставке с идентити, а если мне нужно сначала вычислить Indentity ? потом показать его в интерфейсе, отчете, и только потом вставить значение с этим идентити.
S>Если — то да, сделаете функцию резервирования идентити. При этом у вас на все 20-30 версий различных СУБД будет 2 или 3 реализации.
S>Заводить ради этого целую кунсткамеру репозиториев крайне невыгодно.

Тут может получиться спор по теме что же важнее курица или яйцо.
Оба подхода boilerplate и общей логики имеют свои плюсы и минусы,
минусы boilerplate — нужно писать больше кода, порой что-то дублировать, плюсы — изменения в одном месте, например конктретной процедуры для работы с конкретной СУБД Oracle, гарантированно не затрагивают другие.
минусы общего кода — каждое изменение нужно тестировать на всех средах которые используют общий код, вместо одной, плюсы — меньше кода писать.
Поэтому тут надо отталкиваться что дороже, 3 раза Copy-Paste сделать, если процедура дублируется, или же 3 раза протестировать на разных средах, практика показывает что у кого-то тестирование дольше и дороже выходит, особенно если ручное.

S>Никакого. Сейлза, который подпишет контракт с фиксированным сроком устранения "дефектов", анально расстреляют за профнепригодность. Взрослые люди понимают, что не бывает ни бездефектного софта, ни возможности за конечное время починить произвольный дефект. Тем более, что нет никакого объективного способа отличить баг от фиче-реквеста.


Можно и так конечно, наверняка есть клиенты для которых риски что сервис выключится и будет 3 дня не работать не критичны для бизнеса. Для личной страницы и drive это не критично, но например опыт есть в банковской сфере там под таким не подпишется, обычно всегда сроки стоят 24 часа на устранение критичных дефектов.

S>Никто не будет бросать всё и тратить десятки тысяч $$$ на то, чтобы спешно выкатить релиз, чинящий мелкое неудобство.


Речь не о мелких неудобствах, а когда например после релиза какого-нибудь патча, у 100 клиентов все работает, а у 101 вдруг неожиданно отвалилось, и не работают платежи и пр, бизнес встал, например раньше у него процедура выполнялась за 50 сек, но после правки общей логики стала выполняться >1 минуты и вылетает на таймаут. В тестах же стоит таймаут 5 минут и ошибка не обнаружена при тестировании.

S>Есть регулярное расписание maintenance releases. Если бага подтверждена, и починка её недорога, то фикс включат в следующий релиз (как правило, ежемесячный).

O>>Как решаются всякие оперативные задачи по обслуживанию базы — переустановки, бэкапы, восстановление, профилактика ?
S>Бэкапы делаются автоматически, по расписанию, которое настраивается при передаче системы в эксплуатацию.
S>Всяке переустановки (это вообще что?) делаются за отдельные деньги службой Professional Services. Если заказчик хочет сэкономить, то сажает свою команду. Либо покупает услуги сопровождения у наших партнёров (например, Datacom).
S>Восстановление из бэкапа означает, как правило, форс-мажор, происходит при участии службы поддержки, и на моей памяти (за 12 лет) происходило считанные разы.

O>>Но коллега где-то тут уже приводил рассказ "чуда" что они берут функцию которая возвращает IQueryable , потом навешивают на нее еще логику, еще логику и т.д.

O>>и потом получают чудо в виде красивого запроса. Но я же понимаю что это не так. Колелега либо вводит намеряно в заблуждение либо сам заблуждается,
O>>может и я заблуждаюсь, но поясню почему я уверен скорее в первых двух — z понимаю же что IQueryable все что может рассказать о запросе это только expression tree и
O>>даже человеку не достаточно этих данных чтобы написать правильный запрос.
O>>По вашему опыту какие данные входные данные нужны для постановки задачи чтобы написать правильный запрос к субд ?
S>Минимальные метаданные о структуре таблиц, плюс знания об особенностях конкретного движка СУБД. Ну, чтобы не лепить connect by там, где надо CTE, и не заменять window functions вычислениями на клиенте.

Нужно понимать статистику данных, чтобы правильно сделать запрос, в СУБД есть планировка по статистике, но она как правило дает не верный результат, т.к. не может предсказывать будущее, это мы знаем что у нас 1000000 полей в день появляется в среднем и какого они свойства, что будет меняться часто и будет уникально всегда, что будет дублироваться.

S>С функциями — почти так же: если у вас многоплатформенность стоит в ultimate goal, то надо думать не только о функциях Oracle, но и о том, как это будет работать на других СУБД.

S>Внезапно может потребоваться пересмотреть структуру базы так, чтобы приложение приемлемо работало на всём спектре.

Да только такое внезапно когда уже сотня клиентов в релизе не всегда дешево обходится, поэтому вариант когда мы на начальном этапе продублировали код и потом заточили под конкретную СУБД выглядит намного дешевле.

O>>Ну мой вариант обозначен в моем первом ответе автору топика — http://rsdn.org/forum/dotnet/7421994.1
Автор: okon
Дата: 17.04.19

O>>Вы с ним не согласны или просто призываете к написанию SQL на Linq2Sql ?
S>Ну ужасный же вариант, не так ли? Вы там просто троеточиями обозначили килобайты совершенно одинакового кода, как будто его нет. А в жизни весь этот код нужно написать, отладить, и поддерживать.
S>Вы попробуйте сесть и по-честному написать обсуждаемые примеры без троеточий. Обратите внимание — коллега Danchik пишет полные решения, которые компилируются и работают. А вы только очерчиваете этаким лёгким движением: "вот здесь у нас будет 15000 loc отборного кода на PL/SQL, написанного высококлассными специалистами в Oracle и в OOAD". "А вот тут — ещё 15000 loc не менее отборного кода, написанного высококлассными специалистами по T-SQL. С хинтами и уникальными функциями".

O>>т.к. задачу можно решить разными способами, а наиболее правильный способ зависит от факторов которые в expression не фигурируют.

S>Например?
O>>Вот об этом и речь, а знания нужны не только о Foreign Key и индексах чтобы построить правильный запрос.
S>Например?

Как я писал выше понимание статистики данных и как она будет меняться во времени. Это основное как мне кажется, но не только это.
Много мелкий но иногда важных факторов от бизнеса клиента до железа на котором все работать будет, то что может помочь принять решение при неоднозначности выбора как лучше написать одну и ту же логику.
У expression этой всей информации не будет, у разработчика как минимум обычно есть понимание или возможность выяснить при проектировании эти детали чтобы даже сравнение двух полей написать одним из возможных способов наиболее оптимально. Логика с expression в идеальном случае будет знать все возможные варианты, но не сможет выбрать правильный.

O>>Оцениваю то что он может, то что и его постоянно надо контролировать и всякими гвоздями потом прибивать если он что-то делает неправильно,

O>>вместо того чтобы спокойно писать чистый SQL который нужно получить в итоге.
S>Ещё раз: это иллюзия, основанная на заблуждениях. В начале карьеры — да, придётся внимательно смотреть на порождаемый SQL. Потом, попривыкнете к инструменту — станет значительно легче.
S>Ну, вот вы когда SQL пишете — вы всегда проверяете планы запросов? Или в уме сразу строите примерный план, и только в сложных случаях смотрите, какой из индексов реально подхватился?
План не всегда коненчо смотрю, но когда проектирую запрос я его запускаю на тестовых данных с реальной базы, если он выполняется на большом объеме за <0.001 сек то план не смотрю, если уже больше, то поглядываю в чем там затык.

S>А ведь SQL — он гораздо менее жёсткий, чем linq2db. Дистанция между запросами в expression tree и в SQL гораздо меньше, чем между SQL и планом его выполнения.


Ну тут получается еще один посредник, так у меня SQL->План, так получается Linq2Db->SQL->План. Если вышла новая версия СУБД то я сразу могу пользовать ее возможности и оптимизировать запрос у конкретного клиента, драйвер linq2db в этот момент может оказаться еще не допилен. Или если вышло и Linq2Db и новая версия Oracle мне надо уже вместо 2х конфигураций (Oracle11/12) поддерживать 4 конфигурации (L2DB1, L2DB2 ) x (Oracle11/12).
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[22]: Архитектура доступа к бд
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.05.19 06:43
Оценка:
Здравствуйте, okon, Вы писали:

O>Тут может получиться спор по теме что же важнее курица или яйцо.

O>Оба подхода boilerplate и общей логики имеют свои плюсы и минусы,
O>минусы boilerplate — нужно писать больше кода, порой что-то дублировать, плюсы — изменения в одном месте, например конктретной процедуры для работы с конкретной СУБД Oracle, гарантированно не затрагивают другие.
Согласен. По моим наблюдениям, требование "изменить только работу только с конкретной СУБД" встречается гораздо реже требования "нужно внести изменения для всех СУБД".
В итоге матожидание расходов в вашем подходе выше в разы.
O>минусы общего кода — каждое изменение нужно тестировать на всех средах которые используют общий код, вместо одной, плюсы — меньше кода писать.
O>Поэтому тут надо отталкиваться что дороже, 3 раза Copy-Paste сделать, если процедура дублируется, или же 3 раза протестировать на разных средах, практика показывает что у кого-то тестирование дольше и дороже выходит, особенно если ручное.
На всякий случай напомню, что даже в случае copy-paste тестировать нужно всё равно все три раза.

O>Можно и так конечно, наверняка есть клиенты для которых риски что сервис выключится и будет 3 дня не работать не критичны для бизнеса. Для личной страницы и drive это не критично, но например опыт есть в банковской сфере там под таким не подпишется, обычно всегда сроки стоят 24 часа на устранение критичных дефектов.

По-моему, вы что-то путаете. 24 часа — это нереальный срок для устранения программной ошибки, если речь не о личной странице.
Не верю я, что банк станет ставить патч, который был инициирован 24 часа назад — а как же acceptance testing?

O>Речь не о мелких неудобствах, а когда например после релиза какого-нибудь патча, у 100 клиентов все работает, а у 101 вдруг неожиданно отвалилось, и не работают платежи и пр, бизнес встал, например раньше у него процедура выполнялась за 50 сек, но после правки общей логики стала выполняться >1 минуты и вылетает на таймаут. В тестах же стоит таймаут 5 минут и ошибка не обнаружена при тестировании.

Ну, во-первых, кто ж ставит в тестах такие таймауты?
Во-вторых, наши партнёры никогда не ставят апдейт без стейджинга. То есть мы даём апдейт, они его накатывают на стейджинг, и от 2 до 4 недель гоняют приёмочные тесты.
В-третьих, когда такое происходит, ни о каких 24 часах речь идти всё равно не может. Примерно 24 часа уйдёт банально на выяснение причин, по которым не работают платежи.
Потом будут предложены меры — например, почему бы не подкрутить таймаут у этого партнёра, если у 100 других всё работает? Это можно сделать прямо сейчас, не дожидаясь сборки хотфикса.
Самое быстрое, что можно сделать в более-менее сложном софте — это 1 неделя от момента обнаружения проблемы до её закрытия.
Потому что ни один бизнес в здравом уме не станет экспериментировать в production, какая бы тяжёлая проблема ни была. Поспешный фикс с частичным обновлением и без тестирования, в 7 случаях из 9 приводит к ухудшению проблемы.

O>Нужно понимать статистику данных, чтобы правильно сделать запрос, в СУБД есть планировка по статистике, но она как правило дает не верный результат, т.к. не может предсказывать будущее, это мы знаем что у нас 1000000 полей в день появляется в среднем и какого они свойства, что будет меняться часто и будет уникально всегда, что будет дублироваться.


Статистика данных есть у СУБД. Это её работа — построить оптимальный план запроса. Я так понял, что вы не доверяете движку, или не умеете его администрировать, поэтому планы запросов жёстко вшиваете вручную хинтами.
Конечно, в таком варианте вы обречены постоянно отставать — как я и говорил, план, оптимальный сегодня, может устареть завтра.
Нормальная, полноценная СУБД, выпущенная после 2003 года, умеет сама считать, что дублируется, что уникально, сколько полей всего, и так далее.
Ваша работа — дать СУБД нормальный SQL, который наиболее адекватно отражает семантику запроса.
Например, запихивать вручную данные во временную таблицу, а потом делать join с ней — это связывать руки оптимизатору. Нормальная СУБД, когда видит запрос типа where airport in ('DME', 'SVO', 'OVB', 'JFK', ....), сама понимает, в какой момент лучше это скинуть в temp table.
И таких примеров — очень много. Работа с СУБД в императивном стиле — это худший вариант вложения средств в софт и зарплату.

O>Да только такое внезапно когда уже сотня клиентов в релизе не всегда дешево обходится, поэтому вариант когда мы на начальном этапе продублировали код и потом заточили под конкретную СУБД выглядит намного дешевле.

Непонятно, как это так — вы вносите изменение в логику, но оно работает только в одной СУБД???? Вам же всё равно придётся всё то же самое придумывать в других СУБД — и как раз дело осложняется тем, что вы сразу написали вещь, удобную в одном конкретном диалекте.

O>Как я писал выше понимание статистики данных и как она будет меняться во времени. Это основное как мне кажется, но не только это.

Попробуйте привести пример запроса, который нужно писать по-разному, в зависимости от статистики данных.

O>Много мелкий но иногда важных факторов от бизнеса клиента до железа на котором все работать будет, то что может помочь принять решение при неоднозначности выбора как лучше написать одну и ту же логику.

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

O>У expression этой всей информации не будет, у разработчика как минимум обычно есть понимание или возможность выяснить при проектировании эти детали чтобы даже сравнение двух полей написать одним из возможных способов наиболее оптимально. Логика с expression в идеальном случае будет знать все возможные варианты, но не сможет выбрать правильный.

С реляционными СУБД работают не так. Задача разработчика — спроектировать структуру базы так, чтобы нужные ему запросы выполнялись с приемлемыми асимптотиками.
Да, ему крайне желательно примерно представлять себе статистику будущих данных. Например, у нас есть табличка с email адресами, и есть запрос типа GetContactsByDomain(domain).
Если мы знаем, что в ней < 1000 записей, и они сами по себе маленькие, то даже full scan будет уместным, и можно писать select * from contacts where email like '%@'+@domainEscaped.
Если мы понимаем, что табличка выходит широкой и длинной, то мы можем захотеть добавить индекс по полю email, заменив table scan на index scan и bookmark lookup.
При этом, отмечу, SQL никак не изменится.
Если мы понимаем, что у нас овердохрена записей, а селективность высока, то мы можем сменить архитектуру хранения — например, порезав email на localpart и domainpart.
Или, если мы хотим уметь искать "все адреса в TLD", типа .co.uk, то можем вообще хранить поле email в reversed виде, и запрос будет вот таким select * from contacts where reversedEmail like @domainReversedEscaped+'%', и index scan превратится в index seek. Преимущество Linq перед любыми репозиториями — в том, что можно написать одну мета-функцию, которая автоматически будет заменять email.EndsWith(...) на вышеприведённую конструкцию, что сделает код значительно более читаемым, удешевив его отладку и поддержку.

S>>Ну, вот вы когда SQL пишете — вы всегда проверяете планы запросов? Или в уме сразу строите примерный план, и только в сложных случаях смотрите, какой из индексов реально подхватился?

O>План не всегда коненчо смотрю, но когда проектирую запрос я его запускаю на тестовых данных с реальной базы, если он выполняется на большом объеме за <0.001 сек то план не смотрю, если уже больше, то поглядываю в чем там затык.
Вот примерно так же вы будете делать и с linq.
O>Ну тут получается еще один посредник, так у меня SQL->План, так получается Linq2Db->SQL->План. Если вышла новая версия СУБД то я сразу могу пользовать ее возможности и оптимизировать запрос у конкретного клиента, драйвер linq2db в этот момент может оказаться еще не допилен. Или если вышло и Linq2Db и новая версия Oracle мне надо уже вместо 2х конфигураций (Oracle11/12) поддерживать 4 конфигурации (L2DB1, L2DB2 ) x (Oracle11/12).
А это то зачем? В ваш проект будет включена та версия l2db, которая выбрана вами.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 07.05.2019 6:44 Sinclair . Предыдущая версия .
Re[23]: Архитектура доступа к бд
От: okon  
Дата: 07.05.19 10:23
Оценка:
едах которые используют общий код, вместо одной, плюсы — меньше кода писать.
O>>Поэтому тут надо отталкиваться что дороже, 3 раза Copy-Paste сделать, если процедура дублируется, или же 3 раза протестировать на разных средах, практика показывает что у кого-то тестирование дольше и дороже выходит, особенно если ручное.
S>На всякий случай напомню, что даже в случае copy-paste тестировать нужно всё равно все три раза.
Верно, но это делается первый раз в любом случае, и нужно будет сделать в обоих вариантах, поэтому это можно "сократить", остается разница которая описана была выше.


S>По-моему, вы что-то путаете. 24 часа — это нереальный срок для устранения программной ошибки, если речь не о личной странице.

S>Не верю я, что банк станет ставить патч, который был инициирован 24 часа назад — а как же acceptance testing?
S>Ну, во-первых, кто ж ставит в тестах такие таймауты?
S>Во-вторых, наши партнёры никогда не ставят апдейт без стейджинга. То есть мы даём апдейт, они его накатывают на стейджинг, и от 2 до 4 недель гоняют приёмочные тесты.
S>В-третьих, когда такое происходит, ни о каких 24 часах речь идти всё равно не может. Примерно 24 часа уйдёт банально на выяснение причин, по которым не работают платежи.
S>Потом будут предложены меры — например, почему бы не подкрутить таймаут у этого партнёра, если у 100 других всё работает? Это можно сделать прямо сейчас, не дожидаясь сборки хотфикса.
Практически так и есть, сначала продукт гоняют на тестовом контуре, это помогает найти ряд проблем до боевой эксплуатации.
Но разница тестовой среды как правило в объеме гененируемых данных, как правило ряд сотрудников либо дублируют операции на тестовом контуре, либо отдельно тестируют по своей методичке.
Основная разница в объемах данных и самих данных, тестовые данные обычно ограничены какой-то синтетической тестовой выборкой, а также их объем как правило ниже боевого.
В итоге на бою все равно возникают неожиданные проблемы.
Устранение дефекта в 24 часа не означает обязательно выпуск нового релиза или обновления, а приведение системы в рабочее состояние, т.е. от хотфикса до отката как было.

O>>Нужно понимать статистику данных, чтобы правильно сделать запрос, в СУБД есть планировка по статистике, но она как правило дает не верный результат, т.к. не может предсказывать будущее, это мы знаем что у нас 1000000 полей в день появляется в среднем и какого они свойства, что будет меняться часто и будет уникально всегда, что будет дублироваться.

S>
S>Статистика данных есть у СУБД. Это её работа — построить оптимальный план запроса. Я так понял, что вы не доверяете движку, или не умеете его администрировать, поэтому планы запросов жёстко вшиваете вручную хинтами.
Статистика есть но регулярно сталкивались с проблемами что план не верный из-за неверной статистики, которую нужно периодически обновлять по мере накопления данных, либо подумать над запросом и написать его иначе с хинтом или без хинта, заранее зная какая будет статистика в будущем, исходя из предметной области и специфики клиента.

S>Конечно, в таком варианте вы обречены постоянно отставать — как я и говорил, план, оптимальный сегодня, может устареть завтра.

S>Нормальная, полноценная СУБД, выпущенная после 2003 года, умеет сама считать, что дублируется, что уникально, сколько полей всего, и так далее.
да она считает но статистика важная для запроса это не только количество данных, но и их представление ( ниже написал об этом ).

O>>Да только такое внезапно когда уже сотня клиентов в релизе не всегда дешево обходится, поэтому вариант когда мы на начальном этапе продублировали код и потом заточили под конкретную СУБД выглядит намного дешевле.

S>Непонятно, как это так — вы вносите изменение в логику, но оно работает только в одной СУБД???? Вам же всё равно придётся всё то же самое придумывать в других СУБД — и как раз дело осложняется тем, что вы сразу написали вещь, удобную в одном конкретном диалекте.
Если меняется общая логика то да, но основная проблема поддержки мультиклиентного софта, что у клиентов разные требования и порой даже противоречащие друг другу.
Это приводит к усложнению логики, практически в любом случае в случае boilerplate нужно продублировать и тестировать все, в случае общей логики нужно наставить условий и также тестировать все.

Когда меняется не общая логика, а выявляется проблема что база работает медленно на новой версии Oracle 11, а на Oracle 10 все хорошо и нужно оптимизировать только запрос под конкретную базу, используя ее новые фичи и специфику, то тут boilerplate выручает, меняем только в одном месте и тестируем только Oracle 11.


O>>Как я писал выше понимание статистики данных и как она будет меняться во времени. Это основное как мне кажется, но не только это.

S>Попробуйте привести пример запроса, который нужно писать по-разному, в зависимости от статистики данных.
Есть много стратегий поиска по полю, написав выражение where A.Equals(B), мы можем понять только что хотим найти эквивалентное значение, но не даем информации о том какую стратегию хотим использовать.
Соотвественно нужно будет либо под каждую стратегию делать extension что не удобно, и проблема начнется когда поведение может отличаться в зависимости от данных, и специфика зависит от клиента/субд например часто проблемы с локализацией бывают с представлением как даты времени так и чисел. В SQL конечно эту стратегию тоже придется указать, но там все возможные фичи под рукой, и не потребуется писать extension на каждый вариант.
Наприемр поиск по дате можно написать D = '05-MAY-2019' и в одной СУБД это корректно преобразуется в дату, для другой же потребуется дополнительные действия чтобы преобразовать формат, например написать что-то тпипа B= to_date('05-MAY-2019', 'dd-MMM-yyyy'), как-то так.


O>>Много мелкий но иногда важных факторов от бизнеса клиента до железа на котором все работать будет, то что может помочь принять решение при неоднозначности выбора как лучше написать одну и ту же логику.

S>Ок, давайте пример, в котором потребуется писать разный SQL для одного и того же запроса на разном железе.
C железом например у клиента не 1Гбит сетка а 100Мбит или разная скорость HDD/SSD, а нужно вытащить/cохранить определенный объем данных.
В итоге необходимо снизить объем XML данных формируемых, например за счет переименования колонок на более короткие.
Или не так много памяти как у другого клиента и табличка среднего размера в кеш уже не помещается и запрос из-за этого выполняется иначе.
Т.е. запросы будут отличаться также как у СУБД бы поддерживала кэш таблиц или не поддерживала.


O>>Ну тут получается еще один посредник, так у меня SQL->План, так получается Linq2Db->SQL->План. Если вышла новая версия СУБД то я сразу могу пользовать ее возможности и оптимизировать запрос у конкретного клиента, драйвер linq2db в этот момент может оказаться еще не допилен. Или если вышло и Linq2Db и новая версия Oracle мне надо уже вместо 2х конфигураций (Oracle11/12) поддерживать 4 конфигурации (L2DB1, L2DB2 ) x (Oracle11/12).

S>А это то зачем? В ваш проект будет включена та версия l2db, которая выбрана вами.

Не все клиенты будут переходить одновременно и сразу на Oracle 12 например, поэтому нужно будет поддерживать разные конфиуграции и лишняя зависимость тут не понятно помогает или мешает.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[24]: Архитектура доступа к бд
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.05.19 15:42
Оценка:
Здравствуйте, okon, Вы писали:

O>едах которые используют общий код, вместо одной, плюсы — меньше кода писать.

O>>>Поэтому тут надо отталкиваться что дороже, 3 раза Copy-Paste сделать, если процедура дублируется, или же 3 раза протестировать на разных средах, практика показывает что у кого-то тестирование дольше и дороже выходит, особенно если ручное.
S>>На всякий случай напомню, что даже в случае copy-paste тестировать нужно всё равно все три раза.
O>Верно, но это делается первый раз в любом случае, и нужно будет сделать в обоих вариантах, поэтому это можно "сократить", остается разница которая описана была выше.
Совершенно верно — в вашем варианте всё ещё нужно делать copy-paste, а точнее — портировать SQL на несколько диалектов.
В подходе linq2db мы просто пишем код 1 (один) раз, и запускаем то самое тестирование, которое стоит одинаково в обоих подходах.

O>Практически так и есть, сначала продукт гоняют на тестовом контуре, это помогает найти ряд проблем до боевой эксплуатации.

O>Но разница тестовой среды как правило в объеме гененируемых данных, как правило ряд сотрудников либо дублируют операции на тестовом контуре, либо отдельно тестируют по своей методичке.
O>Основная разница в объемах данных и самих данных, тестовые данные обычно ограничены какой-то синтетической тестовой выборкой, а также их объем как правило ниже боевого.
O>В итоге на бою все равно возникают неожиданные проблемы.
O>Устранение дефекта в 24 часа не означает обязательно выпуск нового релиза или обновления, а приведение системы в рабочее состояние, т.е. от хотфикса до отката как было.
Откат как было делается вообще независимо от разработчиков и используемой технологии.
Хотфикс в любом случае требует тестирования — потому что иначе его нельзя включать в mainstream, а невключение в mainstream наращивает технический долг и убивает продукт, потому что через пять лет у вас будет 800 уникальных наборов установленных хотфиксов на 100 инсталляций, и никто не в состоянии сказать, как вообще должно работать приложение.
Если анус реально горит, и другого выхода нет, то можно отдать партнёру и ограниченно-протестированный хотфикс.
То есть на link2db вы точно так же делаете фикс, тестируете его на конкретной СУБД с конкретными настройками приложения, и отдаёте конкретному кастомеру. (Это всё равно будет не 24 часа, но и не 1-2 месяца).
А потом, не торопясь, в рамках обычной регрессии, прогоняете его на остальных поддерживаемых СУБД, корректируете по необходимости, и коммитите в мейнстрим.
O>Статистика есть но регулярно сталкивались с проблемами что план не верный из-за неверной статистики, которую нужно периодически обновлять по мере накопления данных, либо подумать над запросом и написать его иначе с хинтом или без хинта, заранее зная какая будет статистика в будущем, исходя из предметной области и специфики клиента.
Честно говоря, я с Ораклом не сталкивался. Но был о нём лучшего мнения. И тем не менее, я не понимаю, почему вам проще прибить гвозями план запроса, чем просто прогнать recompute statistics или что там у Оракла применяется для этого дела. Раз уж он не умеет самообслуживанием заниматься.
По моему опыту, это очень дорогостоящий подход. Дешевле всего — работа СУБД. У неё нет зарплаты, поэтому всё, что она умеет, должна делать она.
Затем идёт работа DBA и IT-персонала. Не потому, что они мало получают, а потому, что один DBA может пасти несколько сотен баз данных. Потратить 2 часа DBA на анализ запросов, и подкрутить индексы/статистику — это 2 часа оплаченной работы. Потратить 2 часа программиста на изменение SQL — это потратить ещё 8 часов QA на прогон тестов; потратить 1 час техдока на обновление документов; и так далее. В целом каждый час разработки стоит примерно 10 часов, с учётом всех стадий релизного конвеера.

O>Если меняется общая логика то да, но основная проблема поддержки мультиклиентного софта, что у клиентов разные требования и порой даже противоречащие друг другу.

O>Это приводит к усложнению логики, практически в любом случае в случае boilerplate нужно продублировать и тестировать все, в случае общей логики нужно наставить условий и также тестировать все.
Нет. В случае общей логики можно юнит-тестировать конкретные куски. Например, нужно протестировать поведение трёх вариантов GetNewId(), и на этом всё. То есть мы знаем, сколько у нас ветвлений, и тестируем только ветвления.
У вас нет нормального способа сказать "А, этот репозиторий — это копипаста вон того репозитория, кроме двух методов, поэтому мы будем тестировать только их"

O>Когда меняется не общая логика, а выявляется проблема что база работает медленно на новой версии Oracle 11, а на Oracle 10 все хорошо и нужно оптимизировать только запрос под конкретную базу, используя ее новые фичи и специфику, то тут boilerplate выручает, меняем только в одном месте и тестируем только Oracle 11.

Интересно. То есть реально бывает так, что новая версия Оркала работает с теми же данными хуже, чем старая???

O>Есть много стратегий поиска по полю, написав выражение where A.Equals(B), мы можем понять только что хотим найти эквивалентное значение, но не даем информации о том какую стратегию хотим использовать.

Что такое "стратегия"?
В SQL мы пишем where A = B. Всё, поехали.

O>Соотвественно нужно будет либо под каждую стратегию делать extension что не удобно, и проблема начнется когда поведение может отличаться в зависимости от данных, и специфика зависит от клиента/субд например часто проблемы с локализацией бывают с представлением как даты времени так и чисел. В SQL конечно эту стратегию тоже придется указать, но там все возможные фичи под рукой, и не потребуется писать extension на каждый вариант.

O>Наприемр поиск по дате можно написать D = '05-MAY-2019' и в одной СУБД это корректно преобразуется в дату, для другой же потребуется дополнительные действия чтобы преобразовать формат, например написать что-то тпипа B= to_date('05-MAY-2019', 'dd-MMM-yyyy'), как-то так.
Вы, наверное, хотели привести какой-то другой пример. Неужто в природе остались СУБД, которые не понимают ANSI формат даты в строковых литералах?
Даже если это так (чему я буду сильно удивлён), то такие вещи рулятся даже не на уровне linq, а на уровне провайдера БД.
Именно для этого придуман механизм параметров (вместо строковой конкатенации). Пожалуйста, не говорите мне, что вы применяете строковую конкатенацию для передачи datetime литералов


O>>>Много мелкий но иногда важных факторов от бизнеса клиента до железа на котором все работать будет, то что может помочь принять решение при неоднозначности выбора как лучше написать одну и ту же логику.

S>>Ок, давайте пример, в котором потребуется писать разный SQL для одного и того же запроса на разном железе.
O>C железом например у клиента не 1Гбит сетка а 100Мбит или разная скорость HDD/SSD, а нужно вытащить/cохранить определенный объем данных.
O>В итоге необходимо снизить объем XML данных формируемых, например за счет переименования колонок на более короткие.
И чем это изменение помешает клиентам, у которых сетка 1гбит и быстрый SSD?

O>Или не так много памяти как у другого клиента и табличка среднего размера в кеш уже не помещается и запрос из-за этого выполняется иначе.

O>Т.е. запросы будут отличаться также как у СУБД бы поддерживала кэш таблиц или не поддерживала.
Я всё ещё жду примера SQL, который нужно писать по разному в зависимости от размера кэша.

O>Не все клиенты будут переходить одновременно и сразу на Oracle 12 например, поэтому нужно будет поддерживать разные конфиуграции и лишняя зависимость тут не понятно помогает или мешает.

По-прежнему непонятно. В вашем приложении версии X идёт linq2db версии Y. Точка. Никогда не бывает так, что клиент поставил ваше приложение версии X, а linq2db — версии Y+1, или наоборот.
Считайте linq частью вашего приложения.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.