我有多个独立的进程,每个进程都向MySQL数据库提交批量插入查询(数百万行),但让它们并发运行比顺序运行要慢得多。
如何限制这些查询的执行,以便一次只能执行一个查询?
我想过检查PROCESSLIST是否包含任何正在运行的查询,但它可能不是在真正的先到先得,先到先得的基础上正确排队查询的最佳方法。
我正在使用C#和MySQL Connector for .NET。
答案 0 :(得分:2)
我猜你正在使用InnoDb(允许你进行并发写入)。 MyISAM只有表级锁定,因此会将写入排队。
我建议采用类似于ruakh的方法,但是你使用数据库中的表来管理锁定。该表将被称为lock_control
在您尝试对表执行批量插入之前,您在此LOCK TABLES lock_control WRITE
表上请求lock_control
。如果您被授予锁定权限,则继续批量写入,然后释放锁定。如果该表被另一个线程写入锁定,则LOCK TABLES
命令将阻塞,直到锁定被释放。
您可以使用直接插入的表进行此锁定,但我相信在您按住锁定时,没有其他线程可以从表中读取。
在数据库中而不是在文件系统上执行此锁定的优点是,您可以从多个客户端计算机进行插入,并且在某种程度上处理MySQL中的锁定/插入感觉更简单。
答案 1 :(得分:1)
创建批量插入服务/类 让客户端将数据丢给它。
它一次只做一个。如果需要,可以回复消息。
你不想让你的数据库窒息到一个线程,这会杀死其他一切。
答案 2 :(得分:1)
不是很多C#-er,我不能说这是否是最好的方法;但如果没有人给出更好的答案,那么对于这种事情,一种常见的,非语言特定的方法是在文件系统上使用临时文件。在执行其中一个INSERT之前,获取文件的写锁定,并在INSERT完成后释放写锁定。 (您将需要使用using
或finally
块。)This answer提供示例代码,用于以阻塞方式在C#中获取写锁定。
答案 3 :(得分:1)
我不确定这是否会有所帮助,但是可以解决。我有一个类似的问题,我的程序由于MySql查询不正常而引发异常。因此,我决定按顺序运行查询,以便后续查询不会失败。我在这里找到了解决方案。 https://docs.microsoft.com/en-us/windows/wsl/wsl2-index-
public class job_queue
{
private ConcurrentQueue<Action> _jobs = new ConcurrentQueue<Action>();
private bool _delegateQueuedOrRunning = false;
public void Enqueue(Action job)
{
lock (_jobs)
{
_jobs.Enqueue(job);
if (!_delegateQueuedOrRunning)
{
_delegateQueuedOrRunning = true;
ThreadPool.UnsafeQueueUserWorkItem(ProcessQueuedItems, null);
}
}
}
private void ProcessQueuedItems(object ignored)
{
while (true)
{
Action item;
lock (_jobs)
{
if (_jobs.Count == 0)
{
_delegateQueuedOrRunning = false;
break;
}
_jobs.TryDequeue(out item);
}
try
{
//do job
item();
}
catch
{
ThreadPool.UnsafeQueueUserWorkItem(ProcessQueuedItems, null);
throw;
}
}
}
}
这是一个在队列中一个接一个地运行方法的类。然后,您将包含Mysql查询的方法添加到job_queue。
var mysql_tasks= new job_queue();
mysql_tasks.Enqueue(() => { Your_MYSQL_METHOD_HERE(); });