简体   繁体   English

MySQL中的长UPDATE查询

[英]long UPDATE query in MySQL

I have to run some mysql update queries and they take quite a long time to run. 我必须运行一些mysql更新查询,它们需要相当长的时间才能运行。 I use a PHP script but each update takes between 40 and 600ms, generally around 250ms. 我使用PHP脚本,但是每次更新需要40到600毫秒,通常约为250毫秒。

I tried to optimize as much as I could but the script still takes more than 30 minutes to run (for 20000 entries in both tables). 我尽力进行了优化,但是脚本仍然需要30分钟以上的时间运行(两个表中的20000个条目)。

This is a part of my PHP script and the UPDATE query: 这是我的PHP脚本和UPDATE查询的一部分:

if (mysql_num_rows($Rmaster) == 1) {
//Start time
    $Qchange_name = 'UPDATE slave SET NewAreaName = "'.$Amaster['AreaName'].'" WHERE Dialcode = "'.$Amain['Dialcode'].'" ORDER BY Dialcode ASC LIMIT 1 ';
    $Rchange_name = mysql_query($Qchange_name, $link);
//end time = 40 to 600ms
}

My SELECT queries are fast and I have an INDEX on Dialcode in both tables 我的SELECT查询速度很快,并且两个表中的Dialcode都有一个INDEX

These are my tables (simplified) : 这些是我的表(简体):

CREATE TABLE IF NOT EXISTS `master` (
  `Dialcode` varchar(11) DEFAULT NULL,
  `AreaName` varchar(45) DEFAULT NULL,
  KEY `Dialcode` (`Dialcode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Table structure for table `slave`
--
CREATE TABLE IF NOT EXISTS `slave` (
  `AreaName` varchar(47) DEFAULT NULL,
  `NewAreaName` varchar(47) NOT NULL,
  `Dialcode` varchar(15) DEFAULT NULL,
  KEY `Dialcode` (`Dialcode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Anything else I could try to make it faster? 还有什么我可以尝试使其更快?

PHP: 5.3.4 的PHP:5.3.4

MySQL: 5.1.53 的MySQL:5.1.53

(I will first try the PDO solution this weekend and update the post) thanks! (我将在本周末首先尝试PDO解决方案并更新帖子)谢谢!

UPDATE: I tried with PDO these 2 different queries: 更新:我尝试了PDO这2个不同的查询:

$Qchange_name = $pdo->prepare('UPDATE slave SET NewAreaName = ? WHERE DIalcode = ?');
$Qchange_name = $pdo->prepare('REPLACE INTO slave SET NewAreaName = ? AND Dialcode = ?');

But it takes around 18 seconds just to do the foreach for 150 rows! 但是只需要进行大约150秒就可以进行前向学习了!

In my main loops I do: 在我的主要循环中,我这样做:

$L4 = array(); // Before the loops
else if ($countQmaster1 == 1) {
   $L4[] = array($Amaster1['AreaName'], $Amain['Dialcode']);        
}

and then at the end of the loops: 然后在循环结束时:

foreach ($L4 as $b){
    $Qchange_name->execute($b); 
}

Also I have Dialcode as PRIMARY INDEX 我也有Dialcode作为PRIMARY INDEX

Is there something I do wrong? 我有做错什么吗?

UPDATE: Isolated the query. 更新:隔离查询。

Here are the files to create the tables and the code. 这是用于创建表和代码的文件。 I isolated the query and reduced the script at the minimum but it still takes 17 seconds to run 150 rows. 我隔离了查询并最小化了脚本,但是运行150行仍然需要17秒。

Do you see anything wrong? 你有什么不对吗? Do you get the same results? 你得到相同的结果吗?

PHP code here or here 此处此处的 PHP代码

Mysql tables to download here or here Mysql表在这里这里下载

I was thinking about a buffer problem? 我在考虑缓冲区问题? I'am running on my local machine and I get some fast and slow updates. 我在本地计算机上运行,​​并且得到了一些快速和缓慢的更新。

1 was executed in 38.87 ms 
2 was executed in 33.05 ms 
3 was executed in 33.17 ms 
4 was executed in 91.42 ms 
5 was executed in 36.17 ms 
6 was executed in 30.23 ms 
7 was executed in 33.15 ms 
8 was executed in 33.21 ms 
9 was executed in 33.22 ms 
10 was executed in 42.72 ms 
11 was executed in 32.12 ms 
12 was executed in 33.04 ms 
13 was executed in 33.14 ms 
14 was executed in 33.2 ms 
15 was executed in 33.2 ms 
16 was executed in 33.16 ms 
17 was executed in 33.25 ms 
18 was executed in 33.2 ms 
19 was executed in 33.12 ms 
20 was executed in 33.25 ms 
21 was executed in 33.15 ms 
22 was executed in 33.21 ms 
23 was executed in 33.16 ms 
24 was executed in 41.54 ms 
25 was executed in 74.79 ms 
26 was executed in 129.35 ms 
27 was executed in 77.65 ms 
28 was executed in 34.06 ms 
29 was executed in 33.21 ms 
30 was executed in 33.2 ms 
31 was executed in 33.17 ms 
32 was executed in 140.5 ms 
33 was executed in 34.04 ms 
34 was executed in 41.53 ms 
35 was executed in 33.23 ms 
36 was executed in 33.14 ms 
37 was executed in 158.06 ms 
38 was executed in 149.8 ms 
39 was executed in 278.14 ms 
40 was executed in 154.52 ms 
41 was executed in 149.71 ms 
42 was executed in 91.45 ms 
43 was executed in 274.55 ms 
44 was executed in 149.77 ms 
45 was executed in 278.46 ms 
46 was executed in 1055.73 ms 
47 was executed in 280.42 ms 
48 was executed in 149.85 ms 
49 was executed in 154.48 ms 
50 was executed in 178.14 ms 
51 was executed in 158.06 ms 
52 was executed in 433.23 ms 
53 was executed in 149.22 ms  
54 was executed in 166.41 ms 
55 was executed in 41.5 ms 
56 was executed in 33.21 ms 
57 was executed in 41.52 ms 
58 was executed in 33.16 ms 
59 was executed in 33.19 ms 
60 was executed in 49.8 ms 
61 was executed in 33.21 ms 
62 was executed in 33.16 ms 
63 was executed in 41.55 ms 
64 was executed in 33.13 ms 
65 was executed in 58.25 ms 
66 was executed in 33.12 ms 
67 was executed in 41.52 ms 
68 was executed in 33.15 ms 
69 was executed in 33.21 ms 
70 was executed in 41.51 ms 
71 was executed in 33.18 ms 
72 was executed in 33.19 ms 
73 was executed in 41.52 ms 
74 was executed in 33.25 ms 
75 was executed in 33.15 ms 
76 was executed in 41.58 ms 
77 was executed in 33.1 ms 
78 was executed in 33.17 ms 
79 was executed in 41.53 ms 
80 was executed in 33.18 ms 
81 was executed in 41.49 ms 
82 was executed in 33.15 ms 
83 was executed in 33.22 ms 
84 was executed in 41.52 ms 
85 was executed in 33.19 ms 
86 was executed in 33.19 ms 
87 was executed in 66.5 ms 
88 was executed in 33.16 ms 
89 was executed in 75.42 ms 
90 was executed in 57.55 ms 
91 was executed in 33.27 ms 
92 was executed in 41.43 ms 
93 was executed in 33.14 ms 
94 was executed in 33.19 ms 
95 was executed in 41.54 ms 
96 was executed in 33.15 ms 
97 was executed in 33.24 ms 
98 was executed in 41.45 ms 
99 was executed in 33.23 ms 
100 was executed in 33.15 ms 
101 was executed in 41.55 ms 
102 was executed in 33.22 ms 
103 was executed in 274.54 ms 
104 was executed in 291.28 ms 
105 was executed in 149.72 ms 
106 was executed in 91.42 ms 
107 was executed in 274.68 ms 
108 was executed in 278.38 ms 
109 was executed in 154.23 ms 
110 was executed in 432.75 ms 
111 was executed in 424.47 ms 
112 was executed in 309.66 ms 
113 was executed in 1101.32 ms 
114 was executed in 327.63 ms 
115 was executed in 116.23 ms 
116 was executed in 34.24 ms 
117 was executed in 33.18 ms 
118 was executed in 65.39 ms 
119 was executed in 34.36 ms 
120 was executed in 30.48 ms 
121 was executed in 35.85 ms 
122 was executed in 33.18 ms 
123 was executed in 41.54 ms 
124 was executed in 33.13 ms 
125 was executed in 33.23 ms 
126 was executed in 41.49 ms 
127 was executed in 83.13 ms 
128 was executed in 33.13 ms 
129 was executed in 41.58 ms 
130 was executed in 33.15 ms 
131 was executed in 33.17 ms 
132 was executed in 41.5 ms 
133 was executed in 33.18 ms 
134 was executed in 41.54 ms 
135 was executed in 33.13 ms 
136 was executed in 33.19 ms 
137 was executed in 41.55 ms 
138 was executed in 33.14 ms 
139 was executed in 33.21 ms 
140 was executed in 41.5 ms 
141 was executed in 33.22 ms 
142 was executed in 33.17 ms 
143 was executed in 41.51 ms 
144 was executed in 33.13 ms 
145 was executed in 33.22 ms 
146 was executed in 41.51 ms 
147 was executed in 75.34 ms 
148 was executed in 39.76 ms 
149 was executed in 34.38 ms  
150 was executed in 33.12 ms 

This script was executed in 13.45 seconds

This is the config: 这是配置:

# The MySQL server
[wampmysqld]
port        = 3306
socket      = /tmp/mysql.sock
query_cache_size=32M
# key_buffer = 16M
max_allowed_packet = 1M
table_cache = 64
sort_buffer_size = 512K
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M

Edit: Solution 编辑:解决方案

Finally after changing ENGINE=InnoDB to MyISAM the query was executed in less than 3 seconds for 20000 rows! 最后,将ENGINE = InnoDB更改为MyISAM之后,不到2秒就对20000行执行了查询!

Thanks @JOHN for your help! 感谢@JOHN的帮助! PDO helped a lot! PDO帮了大忙!

Use prepared statements (eg mysqli or PDO implementation) always if possible , they are much more efficient, saves you from sql-injections and so on. 如果可能的话 ,请始终使用prepared statements (例如mysqliPDO实现),它们将更加高效,从而避免了sql注入等问题。 Also, consider using mysqli extension, mysql is considered outdated. 另外,考虑使用mysqli扩展名,认为mysql已过时。

One more thing to consider: how do you get those $Amaster and Amain values? 还有一两件事要考虑:你是怎么得到那些$AmasterAmain值? Are they stored in script or retrieved for each row individually? 它们是存储在脚本中还是单独为每一行检索?

In more detail: 更详细地:

Each time you execute a query with mysql_query , database perform request planning. 每次使用mysql_query执行查询时,数据库都会执行请求计划。 For queries that affect small number of rows, planning can take much time compared to the execution itself (don't have any statistics here, but I believe it might be times of magnitude in case of complicated queries and short output). 对于影响少量行的查询,与执行本身相比,计划可能要花费很多时间(这里没有任何统计信息,但是我认为在复杂查询和短输出的情况下,这可能是很重要的时间)。 So, if you are to execute a huge number of similar queries - it's quite inefficient since planning is performed for each query. 因此,如果您要执行大量类似的查询-由于每个查询都要执行计划,因此效率很低。

To avoid this, you should use prepared statements. 为了避免这种情况,您应该使用准备好的语句。 The idea behind this is to create a named object that can cache the plan for the query and skip the planning process, jumping right to the execution step. 其背后的想法是创建一个命名对象,该对象可以缓存查询计划,并跳过计划过程,直接跳至执行步骤。

In practice I've faced a situation when using prepared statements increased the speed of execution about hundred times compared to raw sql queries (about 100000 records) 在实践中,我遇到了一种情况,与原始sql查询(约100000条记录)相比,使用准备好的语句将执行速度提高了约100倍。

There should be support for prepared statements in the DBMS, but as far as I know they are supported in Mysql 5.0 . 在DBMS中应该支持预备语句,但是据我所知,Mysql 5.0支持它们。

Some samples 一些样品

$pdo = new PDO(/*your database connection properties here*/);
$update_stmt = $pdo->prepare("UPDATE slave SET NewAreaName = ? WHERE Dialcode = ? ORDER BY Dialcode ASC LIMIT 1");

/*Iterate over $Rmaster  as you do it now{*/
    $update_stmt->execute(array($Amaster['AreaName'], $Amain['AreaCode']));
/*}*/

Your problems probably result from issuing >20000+1 queries to your database. 您的问题可能是由于向数据库发出了> 20000 + 1个查询。

If possible try to generalize your update statement, to cover multiple rows at once. 如果可能,请尝试概括您的update语句,以一次覆盖多行。 Thus you could reduce your overall number of queries. 因此,您可以减少查询的总数。

First of all, you should use primary keys in every single table you have. 首先,应该在每个表中使用主键。

If you change master.DialCode to a not null primary key, it will already help a lot. 如果将master.DialCode更改为不为null的主键,它将已经很有帮助。

Is slave.DialCode also unique? slave.DialCode是否也唯一? if not, why would you have order by and limit in the query? 如果不是,为什么要在查询中按订单和限额订购?

When you have primary keys, you can try to bundle more records (like 100 or something) and update them at once with replace into. 当您拥有主键时,您可以尝试捆绑更多记录(例如100条记录或类似记录),并使用replace into一次更新它们。

REPLACE INTO slave (DialCode, NewAreaName) Values
('code1','name1'),
('code2','name2'),
('code3','name3');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM