我有一个mysql表,在这个表上有一列(numviews),它经常更新(相同的更新查询在循环中运行)。它需要花费大量时间超过2秒,我无法找到如何改进这一点,因为它影响/减慢我的应用程序也依赖于此表。这是mysql表。
注意:它是一个innodb表,没有其他慢查询。此表位于mariadb galera集群下。我也有 300 最大连接数。在任何时候,全球联系都不会超过170/180。
CREATE TABLE `data_table` (
`site` VARCHAR(100) NOT NULL DEFAULT '',
`active` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
`numclicks` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`numviews` INT(20) UNSIGNED NOT NULL DEFAULT '0',
`country` VARCHAR(200) DEFAULT NULL,
`viewcount` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`name` VARCHAR(150) NOT NULL DEFAULT '',
`comments` TEXT NOT NULL,
`boost` FLOAT DEFAULT '0',
`daily_limit` INT(11) DEFAULT '0',
PRIMARY KEY (`site`)
) ENGINE=INNODB DEFAULT CHARSET=latin1
这是在循环上运行的mysql更新查询(在该表上运行的查询大约是以下查询的50倍)。
UPDATE data_table set numviews = numviews + 1 where site='xyz';
Query OK, 1 row affected (2.57 sec)
Rows matched: 1 Changed: 1 Warnings: 0
SELECT site,active,numclicks,numviews,country,viewcount FROM data_table WHERE site='xyz'\G
*************************** 1. ROW ***************************
site: xyz
active: 1
numclicks: 130406
numviews: 48962
country: |xx yy |
viewcount: 134022
编辑:我也可以看到一些死锁。
------- TRX HAS BEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3020 page no 10 n bits 120 index `PRIMARY` of table `data_table`trx table locks 1 total table locks 47 trx id 71211631903 lock_mode X locks rec but not gap waiting lock hold time 2 wait time before grant 0
------------------
---TRANSACTION 71211631885, ACTIVE 2 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 1083597, OS thread handle 0x7f782a335700, query id 184464304 machine1 XX.XX.XX.XX user updating
UPDATE data_table set numviews = numviews + 1 where site='xyz'
Trx #rec lock waits 12 #table lock waits 0
Trx total rec lock wait time 12 SEC
Trx total table lock wait time 0 SEC
------- TRX HAS BEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3020 page no 10 n bits 120 index `PRIMARY` of table `data_table` trx table locks 1 total table locks 47 trx id 71211631885 lock_mode X locks rec but not gap waiting lock hold time 2 wait time before grant 0
------------------
---TRANSACTION 71211631883, ACTIVE 2 sec
mysql tables in use 1, locked 1
2 lock struct(s), heap size 360, 1 row lock(s), undo log entries 1
MySQL thread id 1082885, OS thread handle 0x7f713e848700, query id 184464302 xxx XX.XX.XX.XX user query end
UPDATE data_table set numviews = numviews + 1 where site='xyz'
Trx #rec lock waits 225 #table lock waits 0
Trx total rec lock wait time 366 SEC
Trx total table lock wait time 0 SEC
任何人都可以帮我改进此更新查询吗?
答案 0 :(得分:0)
您实际上并不需要这样做,您要做的是更新列或增加num_views
列。我的意思是,假设您循环1000次并执行UPDATE
;而是执行单个update
,其值1000表示set numviews = 1000 + 1
(OR),换句话说,如果您拥有总观看次数值,则可以执行单UPDATE
次操作。如果是这样,那么下面的代码将执行相同的
UPDATE data_table set numviews = total_views + 1 where site='xyz';
答案 1 :(得分:0)
快速更改的计数器(点击次数,视图)应位于单独的表格中。这样,不需要这些列的查询(读取和写入)就不会干扰它们。
从任何交易中删除UPDATE
- 将其作为自己的交易。
您的Galera节点相隔多远?如果它们是100ms的越野,则每秒只能进行10次这样的更新。如果是你的情况,请阅读我的high speed ingestion blog;然后我们可以讨论如何在Galera上使用MyISAM来提高UPDATEs
的吞吐量。
答案 2 :(得分:-1)
确保站点列具有索引,或者如果您可以按ID而不是名称确定站点,则可以更好地改进它。创建ID并将其设置为主键。此外,如果只有一个站点,您可以使用LIMIT 1进行一些改进。但是我不确定。也许您可以使用PDO来改进它,以便在循环运行时使用不同的值准备相同的请求。