如何对MySQL查询进行排队以使它们成为顺序而不是并发,并防止过多的I / O使用?

时间:2011-11-29 17:50:17

标签: c# mysql sql performance concurrency

我有多个独立的进程,每个进程都向MySQL数据库提交批量插入查询(数百万行),但让它们并发运行比顺序运行要慢得多。

如何限制这些查询的执行,以便一次只能执行一个查询?

我想过检查PROCESSLIST是否包含任何正在运行的查询,但它可能不是在真正的先到先得,先到先得的基础上正确排队查询的最佳方法。

我正在使用C#和MySQL Connector for .NET。

4 个答案:

答案 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完成后释放写锁定。 (您将需要使用usingfinally块。)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(); });