【发布时间】:2011-08-09 18:31:09
【问题描述】:
我正在请求针对以下问题的 PHP 解决方案:
我在数据库中有大约 15 个表,每个表有 10-50 百万行,总和为 2 亿行,列 userID、B、C、D。
我还有 9 个其他表,其中包含 userID、fbID 列。每个表有大约 200 万行。从 userID 到 fbID 存在一对一的映射。
我的目标是输出包含 fbID、B、C、D 列的 2 亿行的文件。
为了做到这一点,我必须搜索所有包含列 userID 和 fbID 的 9 个表,因为 userID 可能在一个表中找到,但在其他表中找不到。一旦在这些表中的任何一个中找到用户 ID,我就可以停止。这部分我使用 SQL 和 PHP。 SQL 查询包含 LIMIT 1,因此每当我找到用户 ID 时我只返回 1 行,因为这些表可以包含具有相同用户 ID 的多行。
不幸的是,这个算法需要 ~60s/1k 行,我需要 ~130 天才能完成。
有没有更有效的方法来做到这一点?
我不是数据库计算时间如何工作的专家,但我想到了一些想法:
-查询所有 9 个表并使用 userID 键和 fBID 值创建一个查找表。
-使用这 9 个表在数据库中创建一个新表,每个用户 ID 有一行,以及相应的 FBID,并通过该表进行搜索。
以下是有关表格的更具体信息:
总计多达 2 亿行的表格(每个看起来像这样):
Column Type Null Default
dtLogTime datetime Yes NULL
iUin int(10) No
B int(10) No
C int(10) No
D int(10) No
索引:
Keyname Type Unique Packed Column Cardinality Collation Null Comment
dtLogTime BTREE No No dtLogTime 323542 A YES
iUin BTREE No No iUin 323542 A
其他 9 个表格之一:
Column Type Null Default Comments
dtLogTime datetime Yes NULL
iUin int(10) No
vFBID varchar(48) No
索引:
Keyname Type Unique Packed Column Cardinality Collation Null Comment
dtLogTime BTREE No No dtLogTime 2179789 A YES
iUin BTREE No No iUin 2179789 A
我尝试过的示例代码:
// returns FBID of iuin
function getFBID($iuin){
$query = sprintf("SELECT vFBID FROM `tbReg` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
mysql_free_result($result);
$query = sprintf("SELECT vFBID FROM `tbOnline` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
mysql_free_result($result);
$query = sprintf("SELECT vFBID FROM `tbConsumeFBC` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
mysql_free_result($result);
$query = sprintf("SELECT vFBID FROM `tbFeed` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
mysql_free_result($result);
$query = sprintf("SELECT vFBID FROM `tbInvite` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
mysql_free_result($result);
$query = sprintf("SELECT vFBID FROM `tbFreeGift` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
mysql_free_result($result);
$query = sprintf("SELECT vFBID FROM `tbUninstall` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
mysql_free_result($result);
$query = sprintf("SELECT vFBID FROM `tbDownload` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
$query = sprintf("SELECT vFBID FROM `tbIUserSource` WHERE iuin = " . $iuin . " LIMIT 1");
$result = mysql_query($query);
if(mysql_num_rows($result) != 0){
$row = mysql_fetch_assoc($result);
return $row['vFBID'];
}
mysql_free_result($result);
}
fwrite($handle, '"Time","FBID","Action","ActionID"' . "\n");
$query = sprintf("SELECT count(dtLogTime) AS length
FROM `tbActionWeeding`");
$result = mysql_query($query);
$row = mysql_fetch_assoc($result);
$length = ceil($row['length'] * 0.0001);
$start = 0;
$i = 0;
while($i++ < 10000)
$query = sprintf("SELECT dtLogTime, iuin, iWeedID
FROM `tbActionWeeding`
LIMIT " . $start . "," . $length);
$result = mysql_query($query);
if (!$result) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query . "\n";
die($message);
}
while($row = mysql_fetch_assoc($result))
fwrite($handle, '"' . $row['dtLogTime'] . '","' . getFBID($row['iuin']) .
'","0","' . $row['iWeedID'] . "\"\n");
mysql_free_result($result);
$start += $length;
}
【问题讨论】:
-
这听起来像
JOIN会帮助你:en.wikipedia.org/wiki/Join_(SQL) -
这个算法是更大的标准化工作的一部分吗?如果没有,我可以建议您考虑一个的好处吗?
-
抱歉,我忘了提到这 9 个表,每个表都有大约 200 万行,我记得我在连接以前项目中的表时遇到了麻烦。
-
您使用的是什么数据库?您最好使用 sqlplus 或 mysql 之类的命令行实用程序。此外,如果性能是连接时的问题,请考虑为连接列编制索引。
-
请澄清:您是否在这 9 个较小的表的
fbID列中从“2 亿行表”中搜索userID列的值?您的目标是只返回大表中的这些行,在 9 个小表中的任何一个中都有匹配的行吗?
标签: php sql database performance