- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
问题略有修改以提高可理解性
我的目标是优化一个 Web 应用程序,该应用程序的数据库设计非常糟糕,而且我无法访问该数据库(我无法更改表或引入新的数据库)。我可以对代码本身、文件系统或通过代理进行操作。通过“优化”我的意思是:减少发送到 webapp 的请求,而不是直接发送到文件系统的请求,将数据库查询保持在最低限度,减少不同 URL 调用的数量(记住缓存)。
让我试着构建一个虚构的例子,只是为了提供一些话题。让我们想象一下这个场景:
person.php?id=x {x=1,..1000000}
时,页面会创建一个指向 show_picture_of_person.php?id=x
的链接. show_picture_of_person.php
将进入一百万行的数据库,这个数据库将通过返回图像告诉我这个人是悲伤还是快乐。我不知道这张图片是什么,除非我从数据库中提取它。如果我从数据库中提取它,我就可以分析它并了解它是一张悲伤的脸还是一张快乐的脸。 show_picture_of_person
函数实际输出图像。数据库还将图像本身存储在一个 blob 中。图片总是 sad.jpg 或 happy.jpg。我想要的不是指向 show_picture_of_person.php?id=x
的一百万个链接,而是有 2 个链接,一个用于 sad.jpg,一个用于 happy.jpg .我想到的可能的解决方案:
show_picture_of_person
组合,保存所有图像,了解哪些是相同的,然后编写一个查找表。我将该查找表放在 php 函数 make_sensible_url("show_picture_of_person.php?id=x") -> happy.jpg
中。此函数将在 person.php
脚本中调用。我担心 php 引擎本身的性能(像这样的数组本身就是一个 50+MB 的文件!)make_sensible_url("show_picture_of_person.php?id=x")
将简单地读取并输出文件的内容。 我喜欢这种方法,因为没有数据库调用和读取 fs 应该比解决方案 1 中的巨大 PHP 数组更快。person.php
,这样就没有指向 show_picture_of_person.php
的链接,而是制作了 data:images
。问题在于,如果我对 person.php
进行了 x 次调用,我仍然对数据库进行了 2 次调用(一次用于 person.php
,一次用于 show_picture_of_person.php
).我只想对数据库进行 x 次调用。这也增加了页面的大小(在我的真实情况下,我在一页中有大约 20 张图片,所以有很多查询和很多字节)你会如何解决这个问题?谢谢!
为了完整起见,这里是原始问题:
This is the scenario:
- a database with various tables with data which is not properly indexed (let's say for this argument's sake that we have 5000 unique objects represented in around 50.000 rows - so duplicates are present)
- we are in a situation in which the database is non modifiable (this also mean that we can't insert another table)
- we have a php app exposing these objects
- there exists around 1 million php calls (all legitimate) which return one of those 5000 objects (e.g.: bad_url.php?id=bar, bad_url.php?id=foo, ..)
- there is no easy way to programmatically decide which of the 5000 objects will be returned
Our goal is to somehow convert the million+ calls to calls which will be giveme.php?id=x, where x is one of the 5000 unique objects.
Just to give you an idea of a theoretical approach:
- we could index all the millions calls and map them with which distinct object is returned
- we can create a hash table or something and create a php function which would work as give_me_nice_url("bad_url.php?....").
- my feeling is that creating an array with such solution would result in a 50-100MB array .. not sure how performant it would be running realtime under load.
My ask for this question is which approach would you use to solve this issue and handle the large data set? Does there exists a better way than a lookup table like in my solution? Remember I can't use a database in the final production setup.
最佳答案
为每条记录创建一个文件的选项很简单,但也非常臃肿。如果您知道图像是 2 个图像之一,则可以大幅减少开销。假设您使用具有 8 位字符编码的文件,这 8 位中的每一位都可以表示快乐(设置为 1)或悲伤(设置为 0)。这已经使您减少了 8。因此,对于一百万个条目 - 您的文件将达到 125K。
然后是读取和写入文件的各个位的情况。执行此操作的几个小函数和一些测试代码...
<?php
error_reporting ( E_ALL );
ini_set ( 'display_errors', 1 );
function getState ( int $user ) {
$fp = fopen ( "users.dat", "c+" );
// Find the character in the file (position is user >> 4,
// which is effectively / 8
fseek($fp, $user >> 4, SEEK_SET );
// Read the single char from the file
$flagByte = fread($fp,1);
// Extract the bit needed
// ord() converts a char to an ascii value ( 0-255)
// If the byte hasn't been read - use PHP 7 ?? to set it to a 0
// $user & 7 gets the bit position and shifts this bit to position 0
// & 1 extracts just this bit
$flag = (ord($flagByte[0]??chr(0)) >> ($user & 7 )) & 1;
fclose($fp);
return $flag;
}
function setState ( int $user, bool $status ) {
$fp = fopen ( "users.dat", "c+" );
fseek($fp, $user >> 4, SEEK_SET );
// Fetch the existing data
$flagByte = fread($fp,1);
$flagByte = ord($flagByte[0]??chr(0));
// Get position of flag
$flag = 1 << ($user & 7 );
// Either set or unset the appropriate bit
if ( $status ) {
$flagByte |= $flag;
}
else {
$flagByte &= ~$flag;
}
fseek($fp, $user >> 4, SEEK_SET );
fwrite($fp, chr($flagByte));
fclose($fp);
}
setState(1, false);
setState(2, true);
setState(3, true);
setState(4, false);
setState(71, true);
setState(600100, false);
setState(600102, true);
echo "User: 1:".getState(1).PHP_EOL;
echo "User: 71:".getState(71).PHP_EOL;
echo "User: 600100:".getState(600100).PHP_EOL;
echo "User: 3:".getState(3).PHP_EOL;
echo "User: 600102:".getState(600102).PHP_EOL;
echo "User: 4:".getState(4).PHP_EOL;
echo "User: 871:".getState(871).PHP_EOL;
echo "User: 3:".getState(3).PHP_EOL;
我确信您可以在代码上进行改进。特别是如果它被放在一个类中,您可以打开文件并关闭文件一次,而不是在每次调用时。但是,如果只测试一条记录,则不会有太大区别。
更新假设您想要针对用户跟踪图像,此方法的添加周期较慢(因为它会检查图像是否已经存在)但访问是更直接的途径。该概念使用 2 个文件,一个用于图像名称列表,一个用于与用户关联的图像。最主要的是在添加新图像时,它会检查图像是否已经存在,如果存在,则返回该图像在文件中的位置。如果没有找到,它只是将它添加到 EOF。所有名称都以 PHP_EOL 结尾,因此通过分配固定 block ,图像名称或浪费的空间没有限制。用户文件只有指向此图像文件的指针,但(为简单起见)这是一个 4 字节无符号整数,因此对于一百万用户来说,这是 4MB - 不算多。
function imageIndex ( string $addImage ): int {
$images = fopen ( "images.dat", "c+" );
while ( true ) {
$pos = ftell($images);
$image = fgets($images);
if ( $image === false || rtrim($image, PHP_EOL) == $addImage ) {
break;
}
}
if ( $image === false ) {
fseek($images, 0, SEEK_END);
$pos = ftell($images);
fwrite($images, $addImage.PHP_EOL);
}
fclose ( $images);
return $pos;
}
function addUserImage ( int $userID, string $image ) {
$users = fopen ( "users.dat", "c+" );
// Fetch image location
$image = imageIndex($image);
// Locate user indicator (4 bytes per user)
$loc = $userID << 2;
fseek($users, $loc);
// Write the location as an unsigned integer (4 bytes)
fwrite($users, pack("L", $image));
fclose ( $users);
}
function fetchUserImage ( int $userID ): string {
$users = fopen ( "users.dat", "c+" );
$images = fopen ( "images.dat", "c+" );
// Locate user indicator
$loc = $userID << 2;
fseek($users, $loc);
$imgRef = fread($users,4);
// Convert the 4 chars to a PHP integer
$imgLoc = unpack("Lloc", $imgRef);
fseek($images, $imgLoc["loc"]);
$image = fgets($images);
fclose ( $users);
fclose ( $images);
return rtrim($image,PHP_EOL);
}
// Create 4000 users with some image
// for ( $i=0; $i<2000; $i++ ) {
// addUserImage($i,"Image{$i}.jpg");
// }
// for ( $i=0; $i<2000; $i++ ) {
// $ino = 2000 - $i;
// addUserImage($i+2000,"Image{$ino}.jpg");
// }
// Fetch the image for 2000 users
for ( $i=0; $i < 4000; $i+=2) {
echo "User {$i} image=".fetchUserImage($i).PHP_EOL;
}
关于php - 您将如何在不重做数据库的情况下使用错误的数据库优化这个遗留 Webapp,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46119699/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!