2 место Заготовка для работы с БД MySQL в кубике C#

  • Автор темы Автор темы WebBot
  • Дата начала Дата начала
  • Теги Теги
    mysql

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 825
Реакции
1 414
Баллы
113
Приветствую!

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

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

Недостатки стандартного кубика/кода

Главный минус - нет возможности управлять открытием/закрытием коннектов/сессией. Каждый кубик/код работы с БД устанавливает соединение, открывает новую сессию, выполняет SQL запрос и закрывает сессию.

Отсюда проблемы:
  • Невозможно выполнить множество запросов в рамках одной сессии с промежуточной обработкой данных. А именно это чаще всего и нужно для нормальной работы в многопотоке.
  • Невозможно получить Id только что вставленной записи (повторный вызов кубика/кода откроет новую сессию где этой информации не будет)
  • Открытие/закрытие подключений/сессий a) занимает доп. время б) создает доп. нагрузку. Если в шаблоне 50 кубиков работы с БД, то это 50 открытий/закрытий подключений/сессий на 1 поток. А если потоков сотни?
Вдобавок:
  • Отсутствие функции экранирования спецсимволов (это обязательно нужно делать перед вставкой строковых данных в таблицу). Может я плохо искал?
  • Насколько я помню код из кубика не хотел работать со списками созданными в C#, а работал только со списками созданными в ZP. Это очень неудобно.
  • Код из кубика тяжел для восприятия - этакая сборная солянка из хоста/логина/пароля/бд/параметров подклобчения/sql запроса/прочих параметров

Итак, наша задача - решить описанные выше недостатки и сделать работу с БД MySQL более простой и наглядной.

Использование заготовки:


Подготовка ZP. Идем в директорию куда установлен ZP и в папке Progs находим файл MySql.Data.dll . Копируем его в папку ExternalAssemblies находящуюся там же.

Далее открываем заготовку и в кубике C# пишем: (далее идут примеры):

Итак, пример(ы) кода:

C#:
Развернуть Свернуть Копировать
string db_host = "localhost";     // хост
string db_user = "root";          // username для подключения к MySQL
string db_pswd = "";              // пароль для подключения к MySQL
string db_database = "mydb";      // название БД с которой будет работа
string db_charset = "utf8";       // кодировка данных в таблицах

// коннект к MySQL и открытие сессии

DB db = new DB(db_host, db_user, db_pswd, db_database, db_charset);

// все что идет ниже выполняется в рамках одного коннекта/сессии ... это очень важно (!)


// получить 1 результат (скаляр)
// для получения 1 результата всегда используем метод getOne

string count = db.getOne("SELECT COUNT(*) FROM accounts WHERE status=0");
project.SendInfoToLog("Кол-во аккаунтов: "+count,true); // выводим в лог ZP

// получить 1 запись ( запись = 1 строка разделенная на столбцы )
// для получения 1 записи/строки всегда используем метод getRow

List<string> row = db.getRow("SELECT first_name, last_name, status FROM accounts WHERE id=1");

if ( row.Count > 0 ){
    project.SendInfoToLog("Имя: "+row[0],true); // выводим в лог ZP
    project.SendInfoToLog("Фамилия: "+row[1],true);  // выводим в лог ZP
    project.SendInfoToLog("Статус: "+row[2],true);  // выводим в лог ZP
}
else {
    project.SendInfoToLog("запись отсутствует",true);  // выводим в лог ZP
}


// для запросов не возвращающих результата (INSERT/UPDATE/LOCK/UNLOCK/...) всегда используем метод query

// лочим таблицу accounts что бы только 1 поток работал с ней
// P.S вы должны лочить все таблицы и их алиасы с которыми собираетесь работать в рамках строго 1 потока ..
// в этом примере работа идет лишь с 1 таблицей, поэтому и лочится только она

db.query("LOCK TABLES accounts WRITE");

// получить набор строк/столбцов
// для получения набора данных всегда используем метод getAll .. второй параметр - разделитель столбцов в строках ... его можно не указывать, по умолчанию он |

// берем 100 акков со status=0 (свободные), которые при этом дольше всех не брались ( ORDER BY check_time )

List<string> data = db.getAll("SELECT id, first_name, last_name FROM accounts WHERE status=0 ORDER BY check_time LIMIT 100","|");

List<string> ids = new List<string>(); // в этот список сохраним только id полученных данных
for(int i=0; i<data.Count; i++){
    var x = data[i].Split('|');
    project.SendInfoToLog("ID: "+x[0],true);
    project.SendInfoToLog("Имя: "+x[1],true);
    project.SendInfoToLog("Фамилия: "+x[2],true);
    project.SendInfoToLog("--------------",true);
    ids.Add(x[0]); // добавляем очередной id в список ids
}

// текущее юникс-время
int unixtime = (int)(DateTime.UtcNow - new DateTime(1970,1,1)).TotalSeconds;

// здесь, например, делаем чекинг id из списка ids на онлайн в ВК и наполнztv список online теми id которые сейчас онлайн
List<string> online = new List<string>();

// меняем статус у тех кто online (только их мы берем в работу)
if ( online.Count > 0 )
db.query("UPDATE accounts SET status=1 WHERE id IN("+string.Join(",",online)+")");

// обновляем время проверки у всех взятых id
if ( ids.Count > 0 )
db.query("UPDATE accounts SET check_time="+unixtime.ToString()+" WHERE id IN("+string.Join(",",ids)+")");

// разлочиваем таблицу
db.query("UNLOCK TABLES");

// пример экранирования спецсимволов в строке (если не экранировать, то одинарная кавычка поломает наш запрос)
string first_name = db.escapeString("Д'артаньян");

// вставка новой записи
db.query("INSERT INTO accounts SET first_name='"+first_name+"'");

// получение Id только что вставленной записи
string acc_id = db.getOne("SELECT LAST_INSERT_ID()");
project.SendInfoToLog("ID вставленной записи: "+acc_id,true);

// завершаем сессию
db.close();

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

К посту приложены 2 файла - mysql_zagotovka.xmlz и primer1.xmlz . В первом файле не реализовывается какая-то конкретная логика, это просто заготовка со встроенным классом + кубик C# с примерами того как используя методы класса коннектиться к БД, делать различные запросы и тд (в общем то же самое что вы видите в примерах в этом посте). Во втором файле (primer1.xmlz) реализована прямо конкретная логика по взятию аккаунтов в работу из БД в многопотоке, там достаточно создать свою таблицу нужной структуры (приведена мной несколькими постами ниже) и подставить свои данные для коннекта к БД. И все, можно юзать в своих проектах!
 
Номер конкурса шаблонов
  1. Четвертый конкурс шаблонов
Уровень сложности
Продвинутый
Категория
  1. Полезно

Вложения

Последнее редактирование:
хотел заглянуть в шаблон, а там минимальная версия 5.33 - можно снять ограничение?
Благодарю.
 
Камрады, в приложенной изначально заготовке ( mysql_zagotovka.xmlz ) не реализовывается какая-то конкретная логика, там просто заготовка со встроенным классом и кубиком C# в котором показывается как с помощью методов встроенного класса коннектиться к БД, делать различные запросы и тд. ( в общем там то же самое что и в стартпосте ).

Для большего понимая добавил в стартпост еще один демонстрационный файл ( primer1.xmlz ) в котором уже реализована прямо конкретная готовая логика по взятию в работу аккаунтов из таблицы БД в многопотоке. То есть там даже думать не нужно, просто создайте таблицу нужной структуры (приведена ниже) и подставьте свои данные для коннекта к БД. Ну и таблицу аккаунтами не забудьте наполнить =);-)

Структура таблицы аккаунтов для этого примера такая:

notepad++_2019-09-10_08-27-31.png
 
Последнее редактирование:
Сейчас один зенноовод через телеграм спросил: можно ли с помощью этой заготовки сделать аналог работы со списком в zennoposter т.е взять, например, первую строку с удалением и по окончании работы добавить ее в конец.

Сказал ему что отвечу тут в теме т.к возможно этот ответ будет полезен и другим новичкам в БД.

Итак, первое что необходимо четко понять - в реляционных системах управления базами данных (к коим относится и MySQL) понятие "первый" и "последний" весьма условные. Это в обычном текстовом файле есть первая и последняя строка, а тут все зависит от вашего SQL запроса. При одном запросе запись может быть первой в результате, при другом последней, а при третьем быть где-то вообще посередине. Поэтому термины первая/последняя или верхняя/нижняя строка тут не совсем подходят! Зафиксировали этот момент у себя в памяти.

Раз первой и последней строки в привычном понимании не существует, то и логика "взять сверху с удалением и положить в конец" тут так же не работает. Эта логика тут трансформируется в другую логику - "взять свободную запись которая дольше всего не использовалась, пометить что она теперь не свободна, поработать с ней, а по окончанию работы сделать ее снова свободной и заменить время ее использования на текущее". То есть тут мы не удаляем физически записи/строки с последующим их добавлением, а просто фиксируем время когда та или иная запись/строка использовалась! Посмотрите на структуру таблицы accounts в предыдущем моем посте, там есть столбец use_time , который как раз и хранит время (в unix формате) использования того или иного аккаунта. Так же там есть столбец status, говорящий о том находится ли аккаунт в данный момент в работе или же он свободен и может быть взят в работу ( 0 - свободен, 1 - в работе). Исходя из этого мы можем составить следующую логику для взятия и использования тех же аккаунтов:
1) лочим таблицу что бы с ней работал только 1 поток
2) берем один свободный аккаунт (имеющий статус=0), который дольше всего не использовался (имеет минимальное время use_time) - все это делается одним простым SQL запросом
3) меняем его статус на 1 (в работе) ... что бы другие потоки его не взяли в работу повторно
4) разлочиваем таблицу
5) работаем с взятым аккаунтом
6) по окончанию работы с аккаунтом вновь меняем его статус на 0 (свободен), а время последнего использования use_time меняем на
текущее

Именно такая логика и реализована в primer1.xmlz, который вы можете скачать из прикреплений стартпоста!
 
Последнее редактирование:
Ответ на еще на один вопрос напишу тут, возможно для новичков он так же будет полезен.

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

Ответ:
Что бы такого не происходило, необходимо в самом первом кубике шаблона создать подключение/сессию и поместить объект db в так называемый context, с помощью которого этот объект можно получить в любом другом кубике C#.

То есть первый кубик шаблона может иметь примерно такой вид:

C#:
Развернуть Свернуть Копировать
string db_host = "localhost";     // хост
string db_user = "root";          // username для подключения к MySQL
string db_pswd = "";              // пароль для подключения к MySQL
string db_database = "mydb";      // название БД с которой будет работа
string db_charset = "utf8";       // кодировка данных в таблицах

DB db = new DB(db_host, db_user, db_pswd, db_database, db_charset);

// сохраняем объект в контексте что бы использовать его в других кубиках
project.Context["db"] = db;

А дальше в любом другом/последующем кубике C# мы можем получить этот объект из контекста и выполнять наши запросы в рамках того же самого подключения/сессии что и была создана первм кубиком.

Пример кубика где мы получаем наш объект из контекста и используем его:

C#:
Развернуть Свернуть Копировать
var db = project.Context["db"]; // получаем объект из контекста

db.query("LOCK TABLES accounts WRITE");

// берем 1 аккаунт имеющий статус = 0 (свободен) и при этом дольше всего не использовался ( OREDER BY use_time )

List<string> row = db.getRow("SELECT id, login, pswd FROM accounts WHERE status=0 ORDER BY use_time LIMIT 1");

if ( row.Count > 0 ){
 
    project.SendInfoToLog("Взяли аккаунт с логином "+row[1]+" в работу",true);
 
    // сохраняем id, логин и пароль в обычные переменные ZP для использования в других кубиках
    project.Variables["acc_id"].Value = row[0];
    project.Variables["acc_login"].Value = row[1];
    project.Variables["acc_pswd"].Value = row[2];
 
    // меняем статус у взятого аккаунта на 1 (это будет означать что он в работе и брать его нельзя)
 
    db.query("UPDATE accounts SET status=1 WHERE id="+row[0]);
}
else {
    project.SendInfoToLog("Не удалось взять аккаунт",true);
    db.query("UNLOCK TABLES");
    throw new Exception();
}

db.query("UNLOCK TABLES");

И если уж мы используем созданный в первом кубике объект в различных других кубиках (тем самым выполняя все запросы в рамках одной сессии), то в Bad End и Good End нам необходимо не забыть закрыть сессию.

Это может выглядеть так - Good End и Bad End ведут к кубику содержащему примерно такой код:
C#:
Развернуть Свернуть Копировать
var db = project.Context["db"];  // получаем объект из контекста

string acc_id = project.Variables["acc_id"].Value;

if ( acc_id != "" ){
 
    // получаем текущее юникс-время
    int unixtime = (int)(DateTime.UtcNow - new DateTime(1970,1,1)).TotalSeconds;
 
    // обратно устанавливаем статус=0 (свободен) и время последнего использования устанавливаем на текущее
    db.query("UPDATE accounts SET status=0, use_time="+unixtime.ToString()+" WHERE id="+acc_id);
}

// завершаем работу с БД
db.close();


На самом деле я сейчас здесь подчистую скопировал код из приложенного шаблона primer1.xmlz , который как раз и разбит на несколько кубиков - в первом подключение к бд и открытие сессии, в другом получение аккаунта, далее произвольные кубики (работа с взятым аккаунтом), а в Bad End и Good End освобождение аккаунта и завершение сессии mysql.

ProjectMaker_2019-09-10_16-34-32.png


В общем можете сами скачать primer1.xmlz и более детально изучить.
 
Последнее редактирование:
может для пг такое сделать ну или на край кликхауз
 
Камрады, обнаружил свой недочет в приложенном ранее файле primer1.xmlz ... кто его ранее качал для изучения - перекачайте, там при копировании куда то одна строка важная потерялась (разлочивание таблицы в случае если аккаунт взять не удалось). Сейчас к стартпосту прикреплена правильная версия, включающая потерявшуюся строку. Всем сорри за неудобство!
 
  • Спасибо
Реакции: Lanidor и vasbka
Из общения с теми кто только планирует начать разбираться с MySQL, могу сделать такой вывод - у большинства новичков нет четкого понимания преимуществ, которые дает работа с БД.

Давайте я попробую эти самые преимущества тут обозначить:

1) Очень высокая надежность хранения данных. Эх, знали бы вы сколько раз я терял данные из обычных списков ZP даже с учетом того, что в ZP есть встроенный механизм для предотвращения подобных действий. Храня данные в MySQL я ни разу не потерял ни единой строки!

2) Позволяет работать с огромным количеством данных. Попробуй нормально работать в многопотоке со стандартным списком ZP (с привязанным файлом) в котором этак 5-10 млн строк и вероятнее всего вы увидите как ваш ZP "умрет" от такого количества строк. А вот MySQL не умрет, 5-10 млн строк это не так уж много для БД. Да что там 5-10 млн, когда я например парсил все группы ВК у меня в таблице было порядка 120 млн записей и ничего не умерло. При огромном кол-ве данных, конечно, есть свои затыки и проблемы, но тем не менее ничего не умирает и при правильном подходе работать можно.

3) Возможность распределить тяжелую работу на несколько ZP. Да, можно иметь один сервер с БД MySQL в котором будут храниться все необходимые для работы данные, а так же 3-5 отдельных машин с ZP, которые будут совместно юзать эту БД. Таким образом работа будет распределена на несколько машин.

4) Возможности языка SQL избавят вас от изобретения велосипеда. Язык запросов к БД называется SQL и позволяет буквально в несколько строчек сделать такие вещи, на реализацию которых вы в ZP потратите немало времени. К тому же, если вы не являетесь папкой-мастером (специалистом) по различным алгоритмам, то вряд ли ваше решение будет работать быстрее чем это сделает MySQL. Не забывайте, что над алгоритмами работы с данными реализованными в мускуле работают реально супер профессионалы своего дела, которые что называется на этом деле собаку съели. Каждая реализация того или иного алгоритма перед внедрением довольно долго тестируется при различных условиях и внедряются только самые лучшие решения.

5) Это реально удобно и экономит кучу времени . Это скорее как продолжение пункта 4... изобретение велосипедов + их отладка всегда занимает кучу времени. Здесь же многие вещи можно просто сделать одним запросом!

Наверное есть и другие преимущества, но сейчас в голову пришли именно эти. ;-) Скажу так - ZP + MySQL это просто бомба! Один раз разобравшись, у вас больше не будет возникать вопроса о том где хранить данные для ваших проектов.;-)
 
Последнее редактирование:
Благодарю! Очень познавательно, а главное вовремя))
Скажите пожалуйста, и-за чего может быть эта ошибка?
Не запускается в зенно вообще, стартует но поток так и остается 0
В прожектмакере также не запускается с начала, работает только если по кубикам нажимать. При старте с начала выдает такую ошибку как на скрине.
Может это из-за версии, у меня 5,28.
Заранее благодарен.
 

Вложения

  • Безымянный.png
    Безымянный.png
    15,7 KB · Просмотры: 901
Последнее редактирование:
@zhekan3
С вашей версией ZP все OK.
Файл MySql.Data.dll скопировали из папки Progs в папку ExternalAssemblies как это описано в стартпосте?

@molotok
Конечно бывают, если укажите неправильные данные для подключения.
Вот, я сейчас для примера указал неправильный логин для подключения (вместо root указал root1) и в PM получил ошибку
2019-09-12_12-11-39.png
 
@zhekan3
С вашей версией ZP все OK.
Файл MySql.Data.dll скопировали из папки Progs в папку ExternalAssemblies как это описано в стартпосте?

@molotok
Конечно бывают, если укажите неправильные данные для подключения.
Вот, я сейчас для примера указал неправильный логин для подключения (вместо root указал root1) и в PM получил ошибку
Посмотреть вложение 41866
Да, файл скопировал, все сделал по инструкции, самое интересное, что если по кубикам нажимать, без начать с начала - работает с базой без проблем, это в прожектмакере, а в зенке не хочет совсем ))
 
@zhekan3
OK, тогда давайте по порядку:
1) Сервер MySQL точно запущен?
2) Данные для подключения (логин/пароль/название базы) в кубике db_connect заменены на ваши?
3) Сама база прописанная в db_connect точно создана ?
4) Таблица accounts в базе создана? Такой структуры как указано в посте #6 ?
 
@zhekan3
OK, тогда давайте по порядку:
1) Сервер MySQL точно запущен?
2) Данные для подключения (логин/пароль/название базы) в кубике db_connect заменены на ваши?
3) Сама база прописанная в db_connect точно создана ?
4) Таблица accounts в базе создана? Такой структуры как указано в посте #6 ?
Сервер MySQL (денвер) запущен, да все так, все настроено правильно.
 
самое интересное, что если по кубикам нажимать, без начать с начала - работает с базой без проблем, это в прожектмакере, а в зенке не хочет совсем ))
Тогда действительно странно. Работает, но без "начать сначала" это что-то новенькое ;-)
Табличка про Debug Thread Error это как я понимаю у вас в PM ?
В ZP никаких табличек не выскакивает, в логе может что-то есть?
Вообще, сам primer1.xmlz он ничего не делает и в ZP должен отрабатывать за долю секунды ... акк берется в работу, дальше там пустой кубик идет в котором я написал что вместо него там может быть все что угодно (какая-то работа с аккаунтом) и дальше работа завершается.
Может у вас в ZP все запускается как нужно и просто шаб отрабатывает за долю секунды (беря акк и ничего не делая завершается) ? И поэтому вы и видите что 0 потоков работает?) Поставьте вместо того кубика который называется "прочти меня", например паузу на 20 сек (для примера будем считать что это и есть какая-то работа с взятым аккаунтом) и проверьте еще раз....
 
  • Спасибо
Реакции: zhekan3
@zhekan3
С вашей версией ZP все OK.
Файл MySql.Data.dll скопировали из папки Progs в папку ExternalAssemblies как это описано в стартпосте?

@molotok
Конечно бывают, если укажите неправильные данные для подключения.
Вот, я сейчас для примера указал неправильный логин для подключения (вместо root указал root1) и в PM получил ошибку
Посмотреть вложение 41866
Во время работы с правильным подключением ошибки\сбои получения данных бывают?
 
  • Спасибо
Реакции: morpheus93
Во время работы с правильным подключением ошибки\сбои получения данных бывают?
Если запросы к базе написаны корректно, то нет.
Единственное что может быть это таймауты ... то есть сервер после подключения ждет что вы ему будете присылать запросы. Если вы их не присылаете в течении таймаута прописанного в конфиге mysql, то он может оборвать коннект.
Поэтому лучше это время в конфиге сразу увеличить.
 
Спрашивали тут как взять случайную строку из таблицы.
Вообще, для этих целей есть специальная функция - RAND, т.е запрос должен выглядеть примерно так:
SQL:
Развернуть Свернуть Копировать
SELECT id, name FROM accounts WHERE status=0 ORDER BY RAND() LIMIT 1
Однако, не вдаваясь в подробности могу сказать что RAND() это очень тяжелая функция, и прежде чем выбрать 1 случайную строку MySQL в любом случае "пробежится" по всем строкам таблицы, что как вы понимаете не есть хорошо с точки зрения производительности. Особенно это будет заметно на больших таблицах.
Впрочем, есть другой способ, он состоит из 2х запросов к таблице, но зато оба эти запроса очень простые и не создают ненужной нагрузки.
1. Узнаем общее кол-во интересуемых нас строк в таблице
2. Генерим на c# случайное число от 0 до числа полученного в первом пункте (не включая само число)
3. Берем 1 строку из таблицы со смещением полученным в пункте 2

Вот так это может выглядеть используя предлагаемую в этой теме заготовку:

C#:
Развернуть Свернуть Копировать
int rows_count = int.Parse(db.getOne("SELECT COUNT(*) FROM accounts WHERE status=0"));
if ( rows_count > 0 ){
   string z = Global.Classes.rnd.Next(0,rows_count).ToString();
   var row = db.getRow("SELECT id, name FROM accounts WHERE status=0 LIMIT "+z+",1");
   // row[0] - id
   // row[1] - name
}
else {
   project.SendInfoToLog("Таблица не содержит нужных нам строк",true);
}
 
Подскажите пожалуйста, у меня есть большая база данных (5-10млн. строк), сейчас сделанный небольшой костыль, что уходит три запроса на взятие строки с удалением + работа с стандартным кубиком работы по БД, можно ли как оптимизировать подобное? Будет ли прирост скорости работы?
Просто почитал вашу тему, увидел что в теории должен быть, но решение под свою задачу не придумал:(
 
Подскажите пожалуйста, у меня есть большая база данных (5-10млн. строк), сейчас сделанный небольшой костыль, что уходит три запроса на взятие строки с удалением + работа с стандартным кубиком работы по БД, можно ли как оптимизировать подобное? Будет ли прирост скорости работы?
Просто почитал вашу тему, увидел что в теории должен быть, но решение под свою задачу не придумал:(
Зачем удалять, если можно установить флаг Занят, или Использован?
Удаляете вы, скорее всего, данных больше, чем пара байт. Но, в идеале, конечно, нужно сравнительное тестирование.
 
Зачем удалять, если можно установить флаг Занят, или Использован?
Удаляете вы, скорее всего, данных больше, чем пара байт. Но, в идеале, конечно, нужно сравнительное тестирование.
Удаляю с той логики, что они по факту больше не нужны, и эти данные раз в пару недель обновляются по окончанию предыдущих. Первый мой опыт работы с БД, поэтому наверное и перенес принцип с файлов, обработал, удалил.
 
Удаляю с той логики, что они по факту больше не нужны, и эти данные раз в пару недель обновляются по окончанию предыдущих. Первый мой опыт работы с БД, поэтому наверное и перенес принцип с файлов, обработал, удалил.
Процедура удаления данных из файла - довольно ресурсоемкая задача. Особенно, построчное удаление. На уровне операционной системы файл постоянно перезаписывается и перечитывается заново.
Когда работа идет в один поток, при современных мощностях это еще приемлемо, но уже в 20-30 потоков разница ощущается.
Но, каждый ССЗБ.
 
Подскажите пожалуйста, у меня есть большая база данных (5-10млн. строк), сейчас сделанный небольшой костыль, что уходит три запроса на взятие строки с удалением + работа с стандартным кубиком работы по БД, можно ли как оптимизировать подобное? Будет ли прирост скорости работы?

1) Если у вас для этих трех запросов используется 3 стандартных кубика, то это три открытия/закрытия соединения/сессии на один поток.. хотя можно обойтись одним ... работая в 1 поток это не критично, но если потоков десятки/сотни то ...
2) Если у вас используются индексы для ускорения запросов, то каждый раз при удалении строки они будут перестраиваться, что занимает время
3) По хорошему для взятия строки с последующим удалением неплохо бы лочить таблицу т.к в теории между запросом взятия и удалением другой поток так же может взять эту строку в работу ... опять же все зависит от реализации
4) @zortexx прав, лучше помечать что строка использована чем ее удалять
 
Последнее редактирование:
1) Если у вас для этих трех запросов используется 3 стандартных кубика, то это три открытия/закрытия соединения/сессии на один поток.. хотя можно обойтись одним ... работая в 1 поток это не критично, но если потоков десятки/сотни то ...
2) Если у вас используются индексы для ускорения запросов, то каждый раз при удалении строки они будут перестраиваться, что занимает время
3) По хорошему для взятия строки с последующим удалением неплохо бы лочить таблицу т.к в теории между запросом взятия и удалением другой поток так же может взять эту строку в работу ... опять же все зависит от реализации
4) @zortexx прав, лучше помечать что строка использована чем ее удалять

1. Работает в 100 потоков, на одну обработку примерно 4-5 секунд примерно, и в рамках одного выполнение 9 проходов, работает 24/7
2. Что-то где-то слышал про индексы, но мой уровень, просто добавить данные в таблицу и начать с ней работать.
3. Миллионы строк, и маленькое время обработки данных взятых данных спасает в данной ситуации, и при опред. условиях дальше нужного не пойдет.
4. Это может ускорить работу?

Я просто обратил внимание, когда таблица становиться 1-3 миллиона [т.е. по моим меркам маленькая], скорость работы увеличивается, а когда загружаешь 50 млн. скорость заметно падает. Увидел вашу тему, решил обратиться, поможет ли мне это, мои познания в этом не очень пока что.
 
1. Работает в 100 потоков, на одну обработку примерно 4-5 секунд примерно, и в рамках одного выполнение 9 проходов, работает 24/7
2. Что-то где-то слышал про индексы, но мой уровень, просто добавить данные в таблицу и начать с ней работать.
3. Миллионы строк, и маленькое время обработки данных взятых данных спасает в данной ситуации, и при опред. условиях дальше нужного не пойдет.
4. Это может ускорить работу?

Я просто обратил внимание, когда таблица становиться 1-3 миллиона [т.е. по моим меркам маленькая], скорость работы увеличивается, а когда загружаешь 50 млн. скорость заметно падает. Увидел вашу тему, решил обратиться, поможет ли мне это, мои познания в этом не очень пока что.
4-5 сек это довольно долго для БД ... если для таблицы созданы правильные индексы и данные берутся правильным запросом использующим эти индексы, то обычно речь идет о долях секунды, даже на больших таблицах. Опять же нужно смотреть конкретную реализацию и запрос которым выбираются данные из таблицы, тут может быть много нюансов.
Если за 1 выполнение у вас делается 9 проходов (а каждый как я понял состоит из 3 отдельных стандартных кубиков работы с БД), то за 1 выполнение у вас проиходит 27 открытий/закрытий сессии ... и это только на 1 поток. Это тоже занимает время. Все это можно делать в рамках одной сессии.
В общем поэкспериментировать не помешает!
 

Кто просматривает тему: (Всего: 0, Пользователи: 0, Гости: 0)