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

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
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) реализована прямо конкретная логика по взятию аккаунтов в работу из БД в многопотоке, там достаточно создать свою таблицу нужной структуры (приведена мной несколькими постами ниже) и подставить свои данные для коннекта к БД. И все, можно юзать в своих проектах!
 
Категория
Полезно
Номер конкурса шаблонов
Четвертый конкурс шаблонов
Уровень сложности
Продвинутый

Вложения

Для запуска проектов требуется программа ZennoPoster или ZennoDroid.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...

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

Последнее редактирование:

Alexmd

Client
Регистрация
10.12.2018
Сообщения
1 022
Благодарностей
1 424
Баллы
113

Master4eg

Client
Регистрация
06.04.2016
Сообщения
421
Благодарностей
122
Баллы
43
Спасибо, как раз хотел разобраться с MySQL+зенка
 
  • Спасибо
Реакции: WebBot

zenno.xxx

Client
Регистрация
05.10.2016
Сообщения
262
Благодарностей
248
Баллы
43
хотел заглянуть в шаблон, а там минимальная версия 5.33 - можно снять ограничение?
Благодарю.
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Камрады, в приложенной изначально заготовке ( mysql_zagotovka.xmlz ) не реализовывается какая-то конкретная логика, там просто заготовка со встроенным классом и кубиком C# в котором показывается как с помощью методов встроенного класса коннектиться к БД, делать различные запросы и тд. ( в общем там то же самое что и в стартпосте ).

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

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

notepad++_2019-09-10_08-27-31.png
 
Последнее редактирование:

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Сейчас один зенноовод через телеграм спросил: можно ли с помощью этой заготовки сделать аналог работы со списком в 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, который вы можете скачать из прикреплений стартпоста!
 
Последнее редактирование:

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Ответ на еще на один вопрос напишу тут, возможно для новичков он так же будет полезен.

Вопрос:
"Вот ты пишешь что если в шаблоне например будет 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 и более детально изучить.
 
Последнее редактирование:

all3xpress

Client
Регистрация
06.03.2019
Сообщения
159
Благодарностей
25
Баллы
18
может для пг такое сделать ну или на край кликхауз
 

WebBot

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

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Из общения с теми кто только планирует начать разбираться с 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 это просто бомба! Один раз разобравшись, у вас больше не будет возникать вопроса о том где хранить данные для ваших проектов.;-)
 
Последнее редактирование:

zhekan3

Client
Регистрация
27.12.2015
Сообщения
32
Благодарностей
4
Баллы
8
Благодарю! Очень познавательно, а главное вовремя))
Скажите пожалуйста, и-за чего может быть эта ошибка?
Не запускается в зенно вообще, стартует но поток так и остается 0
В прожектмакере также не запускается с начала, работает только если по кубикам нажимать. При старте с начала выдает такую ошибку как на скрине.
Может это из-за версии, у меня 5,28.
Заранее благодарен.
 

Вложения

Последнее редактирование:

molotok

Client
Регистрация
17.04.2015
Сообщения
733
Благодарностей
358
Баллы
63
А ошибки при подключения к базе бывают?
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
@zhekan3
С вашей версией ZP все OK.
Файл MySql.Data.dll скопировали из папки Progs в папку ExternalAssemblies как это описано в стартпосте?

@molotok
Конечно бывают, если укажите неправильные данные для подключения.
Вот, я сейчас для примера указал неправильный логин для подключения (вместо root указал root1) и в PM получил ошибку
2019-09-12_12-11-39.png
 

zhekan3

Client
Регистрация
27.12.2015
Сообщения
32
Благодарностей
4
Баллы
8
@zhekan3
С вашей версией ZP все OK.
Файл MySql.Data.dll скопировали из папки Progs в папку ExternalAssemblies как это описано в стартпосте?

@molotok
Конечно бывают, если укажите неправильные данные для подключения.
Вот, я сейчас для примера указал неправильный логин для подключения (вместо root указал root1) и в PM получил ошибку
Посмотреть вложение 41866
Да, файл скопировал, все сделал по инструкции, самое интересное, что если по кубикам нажимать, без начать с начала - работает с базой без проблем, это в прожектмакере, а в зенке не хочет совсем ))
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
@zhekan3
OK, тогда давайте по порядку:
1) Сервер MySQL точно запущен?
2) Данные для подключения (логин/пароль/название базы) в кубике db_connect заменены на ваши?
3) Сама база прописанная в db_connect точно создана ?
4) Таблица accounts в базе создана? Такой структуры как указано в посте #6 ?
 

zhekan3

Client
Регистрация
27.12.2015
Сообщения
32
Благодарностей
4
Баллы
8
@zhekan3
OK, тогда давайте по порядку:
1) Сервер MySQL точно запущен?
2) Данные для подключения (логин/пароль/название базы) в кубике db_connect заменены на ваши?
3) Сама база прописанная в db_connect точно создана ?
4) Таблица accounts в базе создана? Такой структуры как указано в посте #6 ?
Сервер MySQL (денвер) запущен, да все так, все настроено правильно.
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
самое интересное, что если по кубикам нажимать, без начать с начала - работает с базой без проблем, это в прожектмакере, а в зенке не хочет совсем ))
Тогда действительно странно. Работает, но без "начать сначала" это что-то новенькое ;-)
Табличка про Debug Thread Error это как я понимаю у вас в PM ?
В ZP никаких табличек не выскакивает, в логе может что-то есть?
Вообще, сам primer1.xmlz он ничего не делает и в ZP должен отрабатывать за долю секунды ... акк берется в работу, дальше там пустой кубик идет в котором я написал что вместо него там может быть все что угодно (какая-то работа с аккаунтом) и дальше работа завершается.
Может у вас в ZP все запускается как нужно и просто шаб отрабатывает за долю секунды (беря акк и ничего не делая завершается) ? И поэтому вы и видите что 0 потоков работает?) Поставьте вместо того кубика который называется "прочти меня", например паузу на 20 сек (для примера будем считать что это и есть какая-то работа с взятым аккаунтом) и проверьте еще раз....
 
  • Спасибо
Реакции: zhekan3

molotok

Client
Регистрация
17.04.2015
Сообщения
733
Благодарностей
358
Баллы
63
@zhekan3
С вашей версией ZP все OK.
Файл MySql.Data.dll скопировали из папки Progs в папку ExternalAssemblies как это описано в стартпосте?

@molotok
Конечно бывают, если укажите неправильные данные для подключения.
Вот, я сейчас для примера указал неправильный логин для подключения (вместо root указал root1) и в PM получил ошибку
Посмотреть вложение 41866
Во время работы с правильным подключением ошибки\сбои получения данных бывают?
 
  • Спасибо
Реакции: morpheus93

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Во время работы с правильным подключением ошибки\сбои получения данных бывают?
Если запросы к базе написаны корректно, то нет.
Единственное что может быть это таймауты ... то есть сервер после подключения ждет что вы ему будете присылать запросы. Если вы их не присылаете в течении таймаута прописанного в конфиге mysql, то он может оборвать коннект.
Поэтому лучше это время в конфиге сразу увеличить.
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Спрашивали тут как взять случайную строку из таблицы.
Вообще, для этих целей есть специальная функция - 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);
}
 

WLDN

Client
Регистрация
09.07.2015
Сообщения
357
Благодарностей
566
Баллы
93
Мой голос за тебя. Спасибо. Сэкономил мне время:ay:
 
  • Спасибо
Реакции: WebBot

LiMe

Client
Регистрация
10.12.2015
Сообщения
618
Благодарностей
339
Баллы
63
Подскажите пожалуйста, у меня есть большая база данных (5-10млн. строк), сейчас сделанный небольшой костыль, что уходит три запроса на взятие строки с удалением + работа с стандартным кубиком работы по БД, можно ли как оптимизировать подобное? Будет ли прирост скорости работы?
Просто почитал вашу тему, увидел что в теории должен быть, но решение под свою задачу не придумал:(
 

zortexx

Client
Регистрация
19.09.2011
Сообщения
2 520
Благодарностей
1 226
Баллы
113
Подскажите пожалуйста, у меня есть большая база данных (5-10млн. строк), сейчас сделанный небольшой костыль, что уходит три запроса на взятие строки с удалением + работа с стандартным кубиком работы по БД, можно ли как оптимизировать подобное? Будет ли прирост скорости работы?
Просто почитал вашу тему, увидел что в теории должен быть, но решение под свою задачу не придумал:(
Зачем удалять, если можно установить флаг Занят, или Использован?
Удаляете вы, скорее всего, данных больше, чем пара байт. Но, в идеале, конечно, нужно сравнительное тестирование.
 

LiMe

Client
Регистрация
10.12.2015
Сообщения
618
Благодарностей
339
Баллы
63
Зачем удалять, если можно установить флаг Занят, или Использован?
Удаляете вы, скорее всего, данных больше, чем пара байт. Но, в идеале, конечно, нужно сравнительное тестирование.
Удаляю с той логики, что они по факту больше не нужны, и эти данные раз в пару недель обновляются по окончанию предыдущих. Первый мой опыт работы с БД, поэтому наверное и перенес принцип с файлов, обработал, удалил.
 

zortexx

Client
Регистрация
19.09.2011
Сообщения
2 520
Благодарностей
1 226
Баллы
113
Удаляю с той логики, что они по факту больше не нужны, и эти данные раз в пару недель обновляются по окончанию предыдущих. Первый мой опыт работы с БД, поэтому наверное и перенес принцип с файлов, обработал, удалил.
Процедура удаления данных из файла - довольно ресурсоемкая задача. Особенно, построчное удаление. На уровне операционной системы файл постоянно перезаписывается и перечитывается заново.
Когда работа идет в один поток, при современных мощностях это еще приемлемо, но уже в 20-30 потоков разница ощущается.
Но, каждый ССЗБ.
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 763
Благодарностей
1 391
Баллы
113
Подскажите пожалуйста, у меня есть большая база данных (5-10млн. строк), сейчас сделанный небольшой костыль, что уходит три запроса на взятие строки с удалением + работа с стандартным кубиком работы по БД, можно ли как оптимизировать подобное? Будет ли прирост скорости работы?
1) Если у вас для этих трех запросов используется 3 стандартных кубика, то это три открытия/закрытия соединения/сессии на один поток.. хотя можно обойтись одним ... работая в 1 поток это не критично, но если потоков десятки/сотни то ...
2) Если у вас используются индексы для ускорения запросов, то каждый раз при удалении строки они будут перестраиваться, что занимает время
3) По хорошему для взятия строки с последующим удалением неплохо бы лочить таблицу т.к в теории между запросом взятия и удалением другой поток так же может взять эту строку в работу ... опять же все зависит от реализации
4) @zortexx прав, лучше помечать что строка использована чем ее удалять
 
Последнее редактирование:

LiMe

Client
Регистрация
10.12.2015
Сообщения
618
Благодарностей
339
Баллы
63
1) Если у вас для этих трех запросов используется 3 стандартных кубика, то это три открытия/закрытия соединения/сессии на один поток.. хотя можно обойтись одним ... работая в 1 поток это не критично, но если потоков десятки/сотни то ...
2) Если у вас используются индексы для ускорения запросов, то каждый раз при удалении строки они будут перестраиваться, что занимает время
3) По хорошему для взятия строки с последующим удалением неплохо бы лочить таблицу т.к в теории между запросом взятия и удалением другой поток так же может взять эту строку в работу ... опять же все зависит от реализации
4) @zortexx прав, лучше помечать что строка использована чем ее удалять
1. Работает в 100 потоков, на одну обработку примерно 4-5 секунд примерно, и в рамках одного выполнение 9 проходов, работает 24/7
2. Что-то где-то слышал про индексы, но мой уровень, просто добавить данные в таблицу и начать с ней работать.
3. Миллионы строк, и маленькое время обработки данных взятых данных спасает в данной ситуации, и при опред. условиях дальше нужного не пойдет.
4. Это может ускорить работу?

Я просто обратил внимание, когда таблица становиться 1-3 миллиона [т.е. по моим меркам маленькая], скорость работы увеличивается, а когда загружаешь 50 млн. скорость заметно падает. Увидел вашу тему, решил обратиться, поможет ли мне это, мои познания в этом не очень пока что.
 

WebBot

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

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

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