MySQL选择或更新行为很奇怪

Ren*_*ann 6 php mysql

我得到了一个非常简单的select语句,例如:

SELECT     id, some_more_fields_that_do_not_matter 
FROM       account 
WHERE      status = '0' 
LIMIT      2
Run Code Online (Sandbox Code Playgroud)

请记住,上面的内容返回以下内容:1,2

我接下来要做的是将每行中的这些行循环并更新一些记录:

UPDATE     account 
SET        connection = $_SESSION['account_id'], 
           status = '1' 
WHERE      id = $row_id
Run Code Online (Sandbox Code Playgroud)

现在,id为1,2的表中的行的状态为"1"(我会检查以确保正确更新的行).如果它没有这样做,我会撤消一切.一旦一切正常,我在第一个位置有一个计数器,在这种情况下为2,所以应该更新2行,并用简单的COUNT(*)检查.此信息也将通过电子邮件发送,例如以下数据(这意味着所有内容都已正确更新):

- Time of update: 2013-09-30 16:30:02
- Total rows to be updated (selected) = 2
- Total rows successfully updated after completing queries = 2
The following id's should have been updated 
(these where returned by the SELECT statement):
1,2
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.现在是奇怪的部分.然而,其他用户的下一个查询有时会返回例如id的1,2(但这是不可能的,因为SELECT语句永远不会返回它们,因为它们不再包含状态'0'.所以会发生什么以下内容:我现在收到一封电子邮件,例如:

- Time of update: 2013-09-30 16:30:39
- Total rows to be updated (selected) = 10
- Total rows successfully updated after completing queries = 8
The following id's should have been updated 
(these where returned by the SELECT statement):
1,2,3,4,5,6,7,8,9,10
Run Code Online (Sandbox Code Playgroud)

现在真的很奇怪1和2是由更新选择的.在大多数情况下,它很好,但很少只是没有,并返回一些已经更新状态为"1"的相同ID.

注意这些更新之间的时间.它甚至不是同一时间.我首先想到的是,这些查询会在同一时间执行(这是不可能的吗?).或者这可能吗?或者它可能在某种程度上是缓存的查询,我应该在我的mysql.conf文件中编辑一些设置?

我从来没有遇到过这个问题,我尝试了各种更新方式,但似乎一直在发生.是否可能以某种方式将这两个查询组合在一个巨大的更新查询中?所有数据都是一样的,并没有做任何奇怪的事情.我希望有人知道这可能导致问题以及为什么这是随机(很少)发生的.

编辑:

我更新了脚本,添加了microtime来检查SELECT, UPDATE and CHECK-(SELECT)一起需要多长时间.

第一位会员(ID 20468)致电:2013-10-01 08:30:10

已正确更新以下2个ID的2/2行: 33412,33395

查询合计0.878005027771秒


第二位会员(ID 10123)致电:2013-10-01 08:30:14

20/22行已正确更新以下22个ID: 33392,33412,33395,33396,41489,130​​11,12555,27971,22811以及更多但不重要的

查询一起使用3.3440849781036秒

现在您看到SELECT再次返回3341233395.


第三位会员(ID 20951)致电:2013-10-01 08:30:16

9/9行已正确更新以下9个ID: 33392,33412,33395,33396,41489,130​​11,12555,27971,22811

查询结合在一起并没有返回任何与我有关的事情

由于我们不知道上次查询花了多长时间,我们只知道第一个和第二个查询应该没有问题正确工作,因为如果你看它们之间有4秒钟.并且执行时间是3.34秒.除此之外,第一个开始于2013-10-01 08:30:17,因为为通话记录的时间(通过电子邮件发送时)是在脚本的末尾.查看查询所花费的时间是从第一个查询的开始到最后一个查询之后的停止,这是在我发送电子邮件之前(当然).

它可能是my.cnf文件中mysql正在做这个奇怪的东西吗?我仍然不明白为什么id没有为最后一次(第三次)调用返回任何执行时间.对此的解决方案是通过首先将它们保存到表中并通过cron作业一次执行一个来对这些操作进行排队.但这并不是我想要的,当一个成员打电话时应该是即时的.感谢你目前的帮助.

无论如何这里是我my.cnf的情况有人有我的建议(服务器安装了16GB RAM):

[client]
port                    = 3306
socket                  = /var/run/mysqld/mysqld.sock

[mysqld_safe] 
socket                  = /var/run/mysqld/mysqld.sock
nice                    = 0

[mysqld]
user                    = mysql
pid-file                = /var/run/mysqld/mysqld.pid
socket                  = /var/run/mysqld/mysqld.sock
port                    = 3306
basedir                 = /usr
datadir                 = /var/lib/mysql
tmpdir                  = /tmp
lc-messages-dir         = /usr/share/mysql
skip-external-locking
key_buffer              = 16M 
max_allowed_packet      = 16M
thread_stack            = 192K
thread_cache_size       = 8
myisam-recover          = BACKUP
max_connections         = 20
query_cache_type        = 1 
query_cache_limit       = 1M 
query_cache_size        = 4M
log_error               = /var/log/mysql/error.log
expire_logs_days        = 10
max_binlog_size         = 100M
innodb_buffer_pool_size = 333M
join_buffer_size        = 128K 
tmp_table_size          = 16M
max_heap_table_size     = 16M
table_cache             = 200

[mysqldump]
quick
quote-names
max_allowed_packet      = 16M

[mysql]
#no-auto-rehash # faster start of mysql but no tab completition

[isamchk]
key_buffer              = 16M

!includedir /etc/mysql/conf.d/
Run Code Online (Sandbox Code Playgroud)

编辑2:

    $recycle_available = $this->Account->Membership->query("
    SELECT Account.id,
    (SELECT COUNT(last_clicks.id) FROM last_clicks WHERE last_clicks.account = Account.id AND last_clicks.roulette = '0' AND last_clicks.date BETWEEN '".$seven_days_back."' AND '".$tomorrow."') AS total, 
    (SELECT COUNT(last_clicks.id)/7 FROM last_clicks WHERE last_clicks.account = Account.id AND last_clicks.roulette = '0' AND last_clicks.date BETWEEN '".$seven_days_back."' AND '".$tomorrow."') AS avg 
    FROM membership AS Membership 
    INNER JOIN account AS Account ON Account.id = Membership.account
    WHERE Account.membership = '0' AND Account.referrer = '0' AND Membership.membership = '1'
    HAVING avg > 0.9
    ORDER BY total DESC");
    foreach($referrals as $key => $value)
    {
        $this->Account->query("UPDATE account SET referrer='".$account_id."', since='".$since_date."', expires='".$value['Account']['expires']."', marker='0', kind='1', auction_amount='".$value['Account']['auction_amount']."' WHERE id='".$recycle_available[$key]['Account']['id']."'");
        $new_referral_id[] = $recycle_available[$key]['Account']['id'];
        $counter++;
    }
    $total_updated = $this->Account->find('count',array('conditions'=>array('Account.id'=>$new_referral_id, 'Account.referrer'=>$account_id, 'Account.kind'=>1)));
Run Code Online (Sandbox Code Playgroud)

baz*_*lic 0

如果不接触数据库,很难说出这种奇怪行为的原因。但更好的方法是在一个查询中完成所有操作:

UPDATE     account 
SET        connection = $_SESSION['account_id'], 
           status = '1' 
WHERE      status = '0'
Run Code Online (Sandbox Code Playgroud)

这很可能会解决您面临的问题。