- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 MySQL 表,用于从各种游戏服务器(Urban Terror)收集玩家数据。收集数据的机器人 24/7 运行,目前该表约有 475,000 多条记录。因此,从 PHP 查询该表变得相当慢。我想知道我可以在数据库方面做些什么来使其尽可能优化,然后我可以专注于查询数据库的应用程序。表格如下:
CREATE TABLE IF NOT EXISTS `people` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(40) NOT NULL,
`ip` int(4) unsigned NOT NULL,
`guid` varchar(32) NOT NULL,
`server` int(4) unsigned NOT NULL,
`date` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `Person` (`name`,`ip`,`guid`),
KEY `server` (`server`),
KEY `date` (`date`),
KEY `PlayerName` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='People that Play on Servers' AUTO_INCREMENT=475843 ;
我将IPv4(ip和服务器)描述为4字节整数,并使用MySQL函数NTOA()等进行编码和解码,我听说这种方式比varchar(15)更快。
guid 是 md5sum、32 个字符的十六进制值。日期存储为 unix 时间戳。
我在名称、IP 和 GUID 上有一个唯一的键,以避免同一玩家重复。
我的 key 设置正确吗?我存储数据的方式有效吗?
这是查询该表的代码。您搜索名称、ip 或 guid,它会抓取查询结果并交叉引用与第一个查询结果中的名称、ip 或 guid 匹配的其他记录,并对每个字段执行此操作。这有点难以解释。但基本上,如果我按名字搜索一名玩家,我会看到他使用过的所有其他名称、他使用过的每个 IP 以及他使用过的每个 GUID。
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
Search: <input type="text" name="query" id="query" /><input type="submit" name="btnSubmit" value="Submit" />
</form>
<?php if (!empty($_POST['query'])) { ?>
<table cellspacing="1" id="1up_people" class="tablesorter" width="300">
<thead>
<tr>
<th>ID</th>
<th>Player Name</th>
<th>Player IP</th>
<th>Player GUID</th>
<th>Server</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<?php
function super_unique($array)
{
$result = array_map("unserialize", array_unique(array_map("serialize", $array)));
foreach ($result as $key => $value)
{
if ( is_array($value) )
{
$result[$key] = super_unique($value);
}
}
return $result;
}
if (!empty($_POST['query'])) {
$query = trim($_POST['query']);
$count = 0;
$people = array();
$link = mysql_connect('localhost', 'mysqluser', 'yea right!');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db("1up");
$sql = "SELECT id, name, INET_NTOA(ip) AS ip, guid, INET_NTOA(server) AS server, date FROM 1up_people WHERE (name LIKE \"%$query%\" OR INET_NTOA(ip) LIKE \"%$query%\" OR guid LIKE \"%$query%\")";
$result = mysql_query($sql, $link);
if (!$result) {
die(mysql_error());
}
// Now take the initial results and parse each column into its own array
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$name = htmlspecialchars($row[1]);
$people[] = array(
'id' => $row[0],
'name' => $name,
'ip' => $row[2],
'guid' => $row[3],
'server' => $row[4],
'date' => $row[5]
);
}
// now for each name, ip, guid in results, find additonal records
$people2 = array();
foreach ($people AS $person) {
$ip = $person['ip'];
$sql = "SELECT id, name, INET_NTOA(ip) AS ip, guid, INET_NTOA(server) AS server, date FROM 1up_people WHERE (ip = \"$ip\")";
$result = mysql_query($sql, $link);
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$name = htmlspecialchars($row[1]);
$people2[] = array(
'id' => $row[0],
'name' => $name,
'ip' => $row[2],
'guid' => $row[3],
'server' => $row[4],
'date' => $row[5]
);
}
}
$people3 = array();
foreach ($people AS $person) {
$guid = $person['guid'];
$sql = "SELECT id, name, INET_NTOA(ip) AS ip, guid, INET_NTOA(server) AS server, date FROM 1up_people WHERE (guid = \"$guid\")";
$result = mysql_query($sql, $link);
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$name = htmlspecialchars($row[1]);
$people3[] = array(
'id' => $row[0],
'name' => $name,
'ip' => $row[2],
'guid' => $row[3],
'server' => $row[4],
'date' => $row[5]
);
}
}
$people4 = array();
foreach ($people AS $person) {
$name = $person['name'];
$sql = "SELECT id, name, INET_NTOA(ip) AS ip, guid, INET_NTOA(server) AS server, date FROM 1up_people WHERE (name = \"$name\")";
$result = mysql_query($sql, $link);
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$name = htmlspecialchars($row[1]);
$people4[] = array(
'id' => $row[0],
'name' => $name,
'ip' => $row[2],
'guid' => $row[3],
'server' => $row[4],
'date' => $row[5]
);
}
}
// Combine people and people2 into just people
$people = array_merge($people, $people2);
$people = array_merge($people, $people3);
$people = array_merge($people, $people4);
$people = super_unique($people);
foreach ($people AS $person) {
$date = ($person['date']) ? date("M d, Y", $person['date']) : 'Before 8/1/10';
echo "<tr>\n";
echo "<td>".$person['id']."</td>";
echo "<td>".$person['name']."</td>";
echo "<td>".$person['ip']."</td>";
echo "<td>".$person['guid']."</td>";
echo "<td>".$person['server']."</td>";
echo "<td>".$date."</td>";
echo "</tr>\n";
$count++;
}
// Find Total Records
//$result = mysql_query("SELECT id FROM 1up_people", $link);
//$total = mysql_num_rows($result);
mysql_close($link);
}
?>
</tbody>
</table>
<p>
<?php
echo $count." Records Found for \"".$_POST['query']."\" out of $total";
?>
</p>
<?php
}
$time_stop = microtime(true);
print("Done (ran for ".round($time_stop-$time_start)." seconds).");
?>
感谢任何帮助!
谢谢。
最佳答案
SELECT id,
name,
Inet_ntoa(ip) AS ip,
guid,
Inet_ntoa(server) AS server,
DATE
FROM 1up_people
WHERE ( name LIKE "%$query%"
OR Inet_ntoa(ip) LIKE "%$query%"
OR guid LIKE "%$query%" )
上述查询的一些问题:
该查询在 where 子句中使用 3 个字段,并在每个字段上使用 OR 条件。 MySQL 一次查询只能使用一个索引。因此,它必须为此查询选择名称或 ip 或 guid 上的索引。即使有复合索引(name、ip、guid),在这种情况下也不能使用它,因为条件是 OR 运算的。执行此类查询的更好方法是使用 UNION。例如。
SELECT <fields> FROM table1 WHERE field1='val1' /*will use index on field1*/
UNION
SELECT <fields> FROM table1 WHERE field2='val2' /*will use index on field2*/
...
SELECT <fields> FROM table1 WHERE fieldn='valn' /*will use index on fieldn*/.
在上面的查询中,您分别对每个字段进行选择,然后对其进行 UNION。这允许使用每个字段上的索引,从而提高查询效率。它的缺点是,如果同一行匹配多个条件,则会得到重复的结果。为了避免这种情况,您可以使用 UNION DISTINCT 而不是 UNION,但会更昂贵,因为 mysql 必须对输出进行重复数据删除。为了使该建议发挥作用,还需要解决下面讨论的问题。 (guid上没有索引,需要建立)。
条件使用 LIKE '%query%'
作为名称和 guid,即开头的通配符 (%)。这意味着即使索引存在也无法使用。当在字符串末尾使用 = 或 % 作为“query%”时,可以使用索引。当 % 用于字符串开头时,将不会使用索引。 (引用:http://dev.mysql.com/doc/refman/5.1/en/mysql-indexes.html)。一种可能的解决方法是最后仅使用通配符或对这些字段使用全文索引。
ip 条件为 INET_NTOA(ip) LIKE "%query%"
。当在字段上使用函数时,无法使用该字段上的任何索引。 MySQL 目前不支持函数式索引。如果需要支持这样的查询,您可能还必须将此字段存储为 varchar 并将其视为类似于名称和 guid。
由于上述问题,查询将始终进行全表扫描并且不会使用任何索引。使用 UNION(如 1 中建议的)不会提供任何改进 2 和 3 没有修复,事实上它可能会损害性能,因为它可能会执行 3 次表扫描而不是 1 次。您可以尝试在(name,guid,ip_string) 并执行查询 MATCH(name, guid, ip_string) AGAINST ("$query")
从代码中我发现,在从上述查询中获取结果后,后续查询将根据该查询的结果触发。我不确定是否需要这样做,因为我认为它不会找到任何新记录。当您搜索 f LIKE "%q%"
并使用结果进行诸如 f='r1'
之类的搜索时,LIKE 条件应该已经捕获了所有出现的 'r1 ' 并且后续查询将仅返回重复的结果。在我看来,可以跳过额外的查询,但可能我遗漏了一些东西。
顺便说一句,不要将 SQL 语句中的查询字符串插入为 name LIKE "%$query%"
。这是不安全的,可用于 SQL 注入(inject)攻击。使用带有绑定(bind)变量的准备好的语句。
关于sql - 帮助优化 MySQL 表(约 500,000 条记录)和 PHP 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4524411/
我需要将大约 25 台客户端设备连接到一台服务器设备(都将是 iOS,尽管 Android 会更好)。我知道这个问题有几种解决方案,我自己倾向于 MultipeerConnectivity,但同时存在
我正在考虑为 Android 开发鸟类目录。它将包含许多图片和音频文件,大约 400Mb。 我是从这个世界开始的,但经过一些阅读后,我没有找到太多关于此类应用程序的信息。我有以下问题: 1.- 我有哪
这可能很难解释几何形状,所以我会小心拼写。这在标准 compas 应用程序和 CLLocationManager 中的数据中可见。 1)纵向手持手机时,假设俯仰角为0° 2) 当相机向上指向天空时(例
我有一个相当大的字典,其中包含大约 4000 万个键,我天真地通过将 {key: value, key: value, ...} 写入文本文件来存储这些键。我没有考虑到我永远无法实际访问这些数据这一事
当我在 Oracle 中使用大于约 600 条记录的“INSERT ALL”查询时,为什么查询性能会急剧下降?你能教我吗? 我使用的是 Spring + Mybatis + Oracle 以下是我的查
我有一个要在每个页面上运行的脚本。要做到这一点非常简单,我只需设置 @include * 即可完成。它显示在每个页面上,由我在代码中分配给它的热键组合激活。它按预期工作,没有问题。 但是,我希望它也可
我正在开发一个 Android 移动应用程序,它具有按顺序向服务器上传文件的功能。 我想在编写客户端服务器通信代码时牢记一个标准。 由于要从移动设备上传的文件大小约为 2MB,我们需要将文件分成多个部
我正在尝试根据在每个数据框中找到的一列(称为“名称”)中的匹配值来连接两个数据框(df1 和 df2) .我已经尝试使用 R 的 inner_join 函数以及 Python 的 pandas mer
我正在寻找一种方法来存储带有时间戳的数据。 每个时间戳可能有 1 到 10 个数据字段。 我可以使用简单的数据解决方案或 SQL 将数据存储为 (time, key, value) 吗?这与我可以存储
我有一个播放流式音频数据的应用程序(如聊天客户端)。该工作流程包括三个简单的步骤: 首先发送文件头信息(采样率、每个样本的位数和 channel 数)。 根据上述参数初始化音频waveout设备。 音
我目前正在为我的大学做一个项目。任务是编写语音识别系统,该系统将在后台的手机上运行,等待几个命令(例如,调用 0 123 ...)。 这是一个 2 个月的项目,因此不必非常准确。可接受的噪音量可以
我想将一个大约 50GB 的大文本文件拆分成多个文件。文件中的数据是这样的-[x=0-9之间的任意整数] xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx
我的团队刚刚开始使用 Mercurial 和中央存储库。我们让 Hudson 构建了“默认”分支的尖端——这基本上是我们的主线。我们的旧 VCS 有一个 checkin 政策,即必须在 checkin
我正在为马尔可夫链蒙特卡罗反演程序实现数据收集。然而,MCMC 运行可能需要一周或更长时间才能完成!在运行开始时打开文件会更好吗: with h5py.File('my_data.hdf5', 'r+
我想读取视频文件并保存为二进制文件并再次写入视频文件。我用 180MB 视频进行了测试。我使用了 fread 函数,但它发生了段错误,因为视频的数组大小很小。 这些是我的问题: 我使用 160*102
我有一个小问题。我有一个包含大约 300 万个城市的表,我需要对其运行 like 查询。 问题是,完成查询大约需要 9 秒。有什么想法可以让它变得非常快吗? 查询是: SELECT * FROM `c
进程从信号处理程序中发送给自身的信号在大约 20 秒内无法传递,然后它被传递了。 可能的原因是什么? 我想知道一般可能的原因。 我正在查看的实际代码是 here 最佳答案 很可能,您正在从信号处理程序
我正在使用“aws-sdk:^2.576.0”和“amazon-qldb-driver-nodejs:0.1.0-preview.2”,并遵循 node-sdk's sample code for q
我有 2 个实体,A 和 B,它们具有多对多关系。 A 实体大约有 10,000 个对象,B 大约有 20 个对象。 基本上,A 对象可以与一个或多个 B 对象相关,并且 B 对象会跟踪它们连接到哪些
我成功创建并启动了这个容器: https://github.com/puckel/docker-airflow 通过运行: docker build --rm --build-arg AIRFLOW_
我是一名优秀的程序员,十分优秀!