PDA

View Full Version : انتخاب اعضای مشابه آرایه با تعداد اعضای زیاد



alirayaneh
چهارشنبه 06 مرداد 1389, 02:37 صبح
سلام دوستان من در حال طرحی یک برنامه امنیتی برای یک سیستم مدیریت محتوا هستم
در قسمتی از کار قصد دارم از یک تیبل رکورد هایی که فیلد fild1=fild1 دارای فیلد 1 مساوی و فیلد 2 نامساوی هستند رو به خروجی ببرم لازمه که ذکر کنم تعداد رکورد های این تیبل بیش از 2 میلیون هست با این حساب تا اونجا که اطلاعات بنده قد میده استفاده از ترکیب حلقه در حلقه منتفی میشه .. (حد اقل اون چیزی که در ذهن منه )
آیا روش دیگری برای این کار وجود داره?
چیزی که من نوشتم و سرور رو خابوند :لبخند: این بود :

اول از دیتا بیس همه رکورد هارو میگرفت و در یک ارایه میریخت بعد با استفاده از حلقه for
به این شکل





for(i=0; i<num_rows; i++){
val1=mysql_fetch_array(query);


fild1-1=val1[filde1];
fild2-1=val1[filde2];

for(b=0; i<num_rows; b++){
val2=mysql_fetch_array(query);

filde1-2=val2[filde2];
filde2-2=val2[filde2];

if("fild1-1"=="fild1-2" && "fild2-1"!="fild2-2"){
echo "val2[filde5]", "and", "val1[filde5]";
}
}
}

rapidpich
چهارشنبه 06 مرداد 1389, 08:33 صبح
سلام



تعداد رکورد های این تیبل بیش از 2 میلیون هست

سرور رو خابوند
دیتابیس رو ساختن برای این کارا عزیز! وگرنه یک فایل هم کار همه رو میتونست راه بندازه .
این چیزیه که تو ذهن منه:



SELECT * FROM `files` as a1 JOIN `files` as a2 ON (a1.type=a2.type AND a1.aid != a2.aid )
WHERE 1

alirayaneh
چهارشنبه 06 مرداد 1389, 11:29 صبح
ضمن تشکر از شما اضافه میکنم ذهن خلاقی دارید .
انشا الله تست میکنیم

alirayaneh
چهارشنبه 06 مرداد 1389, 12:14 عصر
من چک کردم ولی باز هم Fatal error: Maximum execution time of 300 seconds exceeded in
میده واجرا نمیشه

بزار واضح تر بگم قصدم چی هست

من از یه تیبل که در اون لوگ ورود و خروج کاربران یک سایت ثبت میشه و حاوی فیلد ip و user_id و date هست
می خوام دو کاربر که ip های مشابه دارن رو انتخاب کنم با این کار کاربرانی که دو اکانت دارن تقریبا مشخص میشن

خوب طبق مشخصاتی هم که در پست قبلی ذکر کردم این تیبل بیش از 2 میلیون رکورد داره که لحضه به لحظه بر اون افزوده میشه با توجه به این که استفاده این کد در یکی از صفحهات سایت قرار میگیرهبنابر این سرعت بارگزاری صفحه هم مهمه ...

mohmadd
چهارشنبه 06 مرداد 1389, 14:06 عصر
query دوستمون درسته ولی چون دو میلیون زیاده خوب زمانش زیاد میشه .
به این حالت هم میتونه باشه :
select distinct * from table join table as a1 on table.user_id!=a1.user_id and table.ip=a1.ip

من خودم الان 1 table با 1 میلیون رکورد ساختم کلی طول کشید تا محاسبه کنه ...

دو میلیون ضربدر دو میلیون باید شرط تستی روی دو حالت انجام بده !!! میشه اینقدر محاسبه :
8,000,000,000,000
نظر من اینه که
زمانی که کاربر لوگین میکنه نام کاربری و ای پی اونو بگیر و بزار تو query
query :
select count(*) from table where ip=$ip and user_id!=$user;
اگه جواب بزرگ تر از 0 شد لوگین نکنه
اینجا حدود 4 میلیون شرط تست میکنه (یعنی حدود 2000000 برابر کمتر)

alirayaneh
چهارشنبه 06 مرداد 1389, 18:26 عصر
با این حساب هیچ راه سهل الوصول تری وجود نداره !؟

پس یا سوال من یخورده غیر منطقی یا هنوز از همه خلاقیت های ذهنمون استفاده نکردیم ( :لبخند: خوشحال تونستم به این سادگی php رو به چالش بکشم :کف:)دوستان یخورده بیشتر تمرکز کنیم شاید بشه این معما رو با یه راه حل ساده تر حل کرد ممکنه یه روزی این سوال برای افراد بیشتر پیش بیاد پس بیاد افتخار ابداع ایده ای برای حل چنین بنبست هایی رو به نام بچه های این سایت ثبت کنیم

mohmadd
چهارشنبه 06 مرداد 1389, 19:45 عصر
شاید بنده منظورتون رو کاملا متوجه نشدم .
شما میخواید نام کاربری کسی که ip یکسانی با ip سایر کاربرا داره(با این حساب کسی از یک ای پی دو تا کاربر درست کرده) به جز نام کاربر خودش رو برگردونه درسته ؟
فقط کافیه count استفاده نکنیم :

select * from table where ip=$ip and user_id!=$user;
من فکر کنم تکنیک های دیگه ای هم هستش , ولی اگه هدفتون اینی که من میگم باشه دیگه چه نیازی هست ؟
در ضمن تو ایران 90% با هر بار وصل شدن به اینترنت یه ای پی دیگه ای میگیرن .
این نشون میده که جواب نمیتونه همیشه درست باشه
بهتره الویت کوکی ها, user agent و خیلی چیز های دیگه رو مد نظر داشته باشیم
الان خیلی از سایت ها اخرین الویتشون ای پیه.

alirayaneh
پنج شنبه 07 مرداد 1389, 00:03 صبح
ضمن تشکر وقدر دانی از پاسخ ها وپیگیری شما
باید عرض کنم منظور من رو در پست قبل تر فرمودید . قصد من این که کل ای پی های موجود در اون تیبل برسی و آی پی های مشابه که یوز غیر مشابه دارند هم هر دو یوزر هم آی پی چاپ بشن

البته استفاده از کوکی ها و سشن ها ایده ی خوبی ولی اون یه سی ام اس 9240 فایلی که دستیابی به نام کوکی ها و سشن ها خیلی پیچیدست البته هسته ی این سی ام اس فکر میکنم php nuke باشه .

ضمن این که دستیابی بهآی پی های مشابه دو یوزر نمیتونه دلیلی برای مسدود کردن یکی از یوزر ها باشه ولی در مواقعی که یکی از یوزر ها به دلیلی مسودد یا اخراج میشه مدیر سایت یوزر های مشکوکی رو که حدس میزنه همون کاربر باشن رو زیر نظر میگیره و در صورت اطمینان اونها رو مسدوود میکنه .

SAMAN_PHP
پنج شنبه 07 مرداد 1389, 00:54 صبح
سلام
منم یه پیشنهاد دارم
با دستور زیر همه اطلاعات جدولو بدون تکرار ip برات میخونه یعنی اگر دو یا چند ip مشابه تو جدول باشه فقط یکی رو برات برمیگردونه . خوب اطلاعاتی که از این طریق استخراج کردی رو توی یه جدول جدید بزار و اولی رو پاک کن .

"SELECT Distinct ip FROM `table` "

وبرای دفه بعد که اگه نخوای دو نام کاربری با یک ip ساخته بشه از کد زیر استفاده کن



$ip = $_SERVER['REMOTE_ADDR'];

$serch=mysql_query("SELECT * FROM `sam_review` WHERE `ip` LIKE '$ip' ");

if(mysql_num_rows($serch)==0)
{
دستور ثبت کاربر

}

mohmadd
پنج شنبه 07 مرداد 1389, 01:22 صبح
خواهش میکنم .. وظیفست, query اول با این تستی که بنده با cpu چهار هسته ای کردم 20 دقیقه طول کشید.و بعد این مدت داشت بازم محاسبه میکرد...
یعنی برای هر فیلد یک بار دو میلیون رو محاسبه میکرد !!
query دوم همون کارو میکنه

هر دو یوزر هم آی پی چاپ بشن یوزری که login میکنه و اسم کاربری و ای پی ش که در دسترسه . درسته ؟
با query دوم هم یوزرهایی که ای پیشون تفاوت نداره و مشابه همدیگه هستن رو میگیره (با نام کاربری یوزری) نشون میده .
اگه فیلد تکراری میده میشه با php درستش کرد
من دقیقا تستش نکردم این query رو اما اگه مشکلی داره بگو


سلام
منم یه پیشنهاد دارم
با دستور زیر همه اطلاعات جدولو بدون تکرار ip برات میخونه یعنی اگر دو یا چند ip مشابه تو جدول باشه فقط یکی رو برات برمیگردونه . خوب اطلاعاتی که از این طریق استخراج کردی رو توی یه جدول جدید بزار و اولی رو پاک کن .سلام دوست عزیز
خوب این query که بازم 2 ساعت طول میکشه که بریزیم تو یه table دیگه ؟؟
درسته ؟

bestirani2
پنج شنبه 07 مرداد 1389, 12:35 عصر
اول بیا یک کوئری بگیر که آی پی هایی که بیش از یک بار در جدول هست رو جمع کنه
بدین صورت


$query = "select ip from useres group by ip having count(ip)!=1";
$result = $con->query($query);سپس کوئری اول رو برای استفاده توسط in آماده کن


$cheat = "(";
while ($row = $result->fetch_row()) {
$cheat .= $row[0].",";
}
$cheat .="null)";در آخر هم توسط یک کوئری دیگه میای هر کسی که شامل آی پی های بالا هست رو شناسایی میکنی


$query = "select * from links where ip in $cheat";
$result = $con->query($query);
while ($row = $result->fetch_row()) {
echo $row[0]."<br>";
}البته میتونی کل این رو یک Select تو در تو بکنی ولی سرعت این حالت در این مورد خاص بیشتر هست

alirayaneh
پنج شنبه 07 مرداد 1389, 12:52 عصر
ضمن تشکر و قدردانی از شما دوستان
الان هر دو رو تست مکنم و گزارش میکنم
راستی محموی جان شما Maximum execution time رو در php.ini روی چند تنظیم کردی ؟ چون من به تنظیمات سرور دسترسی ندارم ومیخوام الان روی لوکال تست کنم
bestirani2 (http://barnamenevis.org/forum/member.php?u=91411) جان شما چطور در تنظیمات php.ini نیازی به تغیر نداره؟

bestirani2
پنج شنبه 07 مرداد 1389, 13:21 عصر
ضمن تشکر و قدردانی از شما دوستان
الان هر دو رو تست مکنم و گزارش میکنم
راستی محموی جان شما Maximum execution time رو در php.ini روی چند تنظیم کردی ؟ چون من به تنظیمات سرور دسترسی ندارم ومیخوام الان روی لوکال تست کنم
bestirani2 (http://barnamenevis.org/forum/member.php?u=91411) جان شما چطور در تنظیمات php.ini نیازی به تغیر نداره؟

این رو روی تنظیمات اولیه تست کنی مشکلی نداره
در کل زمان زیادی برای انجام نمیبره

در مورد تنظیمات هم اگه از mysqli استفاده کنی میتونی بگی


$mysqli = mysqli_init();
mysqli_options($mysqli,MYSQLI_OPT_CONNECT_TIMEOUT, int time);

و به جای int time زمانی رو که میخوای انجام بشه رو بزنی و نیازی به دسترس به تنظیمات سرور نیست فقط بعدش حتماً باید با


mysqli_real_connect

به دیتابیس وصل بشی

alirayaneh
پنج شنبه 07 مرداد 1389, 13:45 عصر
bestirani2 (http://barnamenevis.org/forum/member.php?u=91411) تشکر میکنم

البته من از mysql استفاده میکنم

ولی در هنگام تست کد های قبلی به مشکل برخوردم این ممکنه ناشی از عدم شناخت من از کدی که اراعه کردید باشه ..

پس من نام تیبل و فیلد های مورد نظر رو ذکر میکنم که اگه براتون مقدور باشه کد مخصوص رو بنویسید ..
اسم تیبل : nsnst_tracked_ips
اسم فیلد آی پی ها : ip_addr
اسم فیلد یوزر آی دی ها : user_id
هست .
اگه محبت کنید در خصوص کدی که نوشتید هم یه توضیح بدید ممنون میشم.چون یخورده برام گنگ بود .

rapidpich
پنج شنبه 07 مرداد 1389, 14:04 عصر
کد در یکی از صفحهات سایت قرار میگیره:متعجب:

cache کن
بعدشم اگه میخای به هر کاربری نشون بدی خب باید
where user_id =123 کنی دیگه
درضمن میتونی اگه زمان لاگین رو هم ثبت میکنی کلا فقط مال هفته پیش رو حساب کنی

bestirani2
پنج شنبه 07 مرداد 1389, 14:07 عصر
bestirani2 (http://barnamenevis.org/forum/member.php?u=91411) تشکر میکنم

البته من از mysql استفاده میکنم

ولی در هنگام تست کد های قبلی به مشکل برخوردم این ممکنه ناشی از عدم شناخت من از کدی که اراعه کردید باشه ..

پس من نام تیبل و فیلد های مورد نظر رو ذکر میکنم که اگه براتون مقدور باشه کد مخصوص رو بنویسید ..
اسم تیبل : nsnst_tracked_ips
اسم فیلد آی پی ها : ip_addr
اسم فیلد یوزر آی دی ها : user_id
هست .
اگه محبت کنید در خصوص کدی که نوشتید هم یه توضیح بدید ممنون میشم.چون یخورده برام گنگ بود .

احتمالاً با mysql وصل شدی و من کدهای را با mysqli نوشتم
برای وصل شدن با کمک mysqli به صورت زیر به دیتایس وصل بشید


$con = new mysqli("localhost", "user", "pass", "dbname");

اینم کد کامل


$con = new mysqli("localhost", "user", "pass", "dbname");
$query = "select ip_addr from nsnst_tracked_ips group by ip_addr having count(ip_addr)!=1";
$result = $con->query($query);
$cheat = "(";
while ($row = $result->fetch_row()) {
$cheat .= $row[0].",";
}
$cheat .="null)";


$query = "select user_id from nsnst_tracked_ips where ip_addr in $cheat";
$result = $con->query($query);
while ($row = $result->fetch_row()) {
echo $row[0]."<br>";
}

alirayaneh
پنج شنبه 07 مرداد 1389, 17:38 عصر
bestirani2 (http://barnamenevis.org/forum/member.php?u=91411) جان ضمن تشکر از پاسخ های سریع الوقوع شما و همچنین قدر دانی از زحمتی که برای نوشتن این کد کشیدید
از آنجا که تا به حال با mysqli کار نکرده بودم بهمین خاطر حدس اینکه این کد مربوط به mysqli باشه رو نمیزدم .. تست میکنم ونتیجه رو گزارش میکنم

rapidpich (http://barnamenevis.org/forum/member.php?u=145252) جان ضمن تشکر از پاسخ شما.
در صورتی که ما لوگ های مربوط به یک هفته رو چک کنیم ممکن فاصله زمانی بین لوگین شدن دو یوزر بیش از یک هفته طول بکشه واصلا ممکنه ماه هم برسه . بنابر این از دقت این روش خود به خود کاسته میشه .
در خصوص "cache کن" اگه امکان داره یه توضیح مختصر بدید که به چه شکل باید عمل کنم؟

mohmadd
پنج شنبه 07 مرداد 1389, 17:49 عصر
یک سئول این query هر دفعه باید اجرا بشه درسته ؟

select ip from useres group by ip having count(ip)!=1
چون من الان اجرا کردم 17.25 ثانیه طول کشید که لیست کنه .

alirayaneh
پنج شنبه 07 مرداد 1389, 17:59 عصر
با همون 2 میلیون رکورد ؟
شما هم این select رو برای mysqli نوشتید ؟

mohmadd
پنج شنبه 07 مرداد 1389, 18:26 عصر
با همون 2 میلیون رکورد ؟
شما هم این select رو برای mysqli نوشتید ؟
خیر بنده اینو تو یک میلیون دویست هزار کاربر تست کردم.
شما تست نکردی ؟
اگه تست نکردی برو تست کن بیا بگو

alirayaneh
پنج شنبه 07 مرداد 1389, 18:35 عصر
شما هم این select رو برای mysqli نوشتید ؟
اخه تا الان میخواستم کد قبلی رو امتحان کنم اومد تیبل مورد نظر رو توی mysqli ایمپورت کنم ایمپورت نمیشه هیچ پیغام خطایی هم نمیده که بدونم برای چی ایمپورت نمیکنه ؟
حجم تیبل هم حدود 10 مگ هست

mohmadd
پنج شنبه 07 مرداد 1389, 18:40 عصر
شما هم این select رو برای mysqli نوشتید ؟
اخه تا الان میخواستم کد قبلی رو امتحان کنم اومد تیبل مورد نظر رو توی mysqli ایمپورت کنم ایمپورت نمیشه هیچ پیغام خطایی هم نمیده که بدونم برای چی ایمپورت نمیکنه ؟
حجم تیبل هم حدود 10 مگ هست
خیر این query رو bestiran نوشته و بنده تو mysql تست کردم .
شما همین روش رو پیش بگیر شاید تو mysqli سرعتش خیلی کمتر باشه و...
من تا حالا با mysqli کار نکردم اگه الان بتونم مال خودم رو ایمپورت کنم روش رو میگم.

bestirani2
پنج شنبه 07 مرداد 1389, 20:39 عصر
یک سئول این query هر دفعه باید اجرا بشه درسته ؟

select ip from useres group by ip having count(ip)!=1چون من الان اجرا کردم 17.25 ثانیه طول کشید که لیست کنه .
این کوئری رو فقط برای زمانی که میخواهدی کاربرانی که آی پی یکسانی دارند باید استفاده کرد
که مدیر یک سایت در نهایت در روز یک بار میخواهد لیست کاربرانی که آی پی یکسانی دارند رو لیست کند که این زمان قابل چشم پوشی هست
در ضمن engine اتون چیه؟

bestirani2
پنج شنبه 07 مرداد 1389, 20:41 عصر
شما هم این select رو برای mysqli نوشتید ؟
اخه تا الان میخواستم کد قبلی رو امتحان کنم اومد تیبل مورد نظر رو توی mysqli ایمپورت کنم ایمپورت نمیشه هیچ پیغام خطایی هم نمیده که بدونم برای چی ایمپورت نمیکنه ؟
حجم تیبل هم حدود 10 مگ هست
mysqli هم به دیتابیس mysql وصل میشه و نیاز به ایمپورت نیست
فقط همون کد رو که دادم رو اطلاعات دیتابیس را وارد کنید تا کار کنه

bestirani2
پنج شنبه 07 مرداد 1389, 20:41 عصر
خیر این query رو bestiran نوشته و بنده تو mysql تست کردم .
شما همین روش رو پیش بگیر شاید تو mysqli سرعتش خیلی کمتر باشه و...
من تا حالا با mysqli کار نکردم اگه الان بتونم مال خودم رو ایمپورت کنم روش رو میگم.
طبق benchmark هایی که من دیدم اکثراً mysqli سریعتر بوده البته تفاوت ها کم و قابل چشم پوشی هست

mohmadd
جمعه 08 مرداد 1389, 00:31 صبح
این کوئری رو فقط برای زمانی که میخواهدی کاربرانی که آی پی یکسانی دارند باید استفاده کرد
که مدیر یک سایت در نهایت در روز یک بار میخواهد لیست کاربرانی که آی پی یکسانی دارند رو لیست کند که این زمان قابل چشم پوشی هست
در ضمن engine اتون چیه؟
یعنی اینکه هر بار که کاربر لوگین میشه این عمل انجام نمیشه ؟
و هر بار که کاربری لوگین میکنه تو ای پی های تکراری جستجو میشه ؟ با توجه به اینکه در پست 11 با while یه query ساختیم.
(شاید که کاربر لوگین شده ای پی ش تو بخش ای پی های غیر مشابه هستش ؟)

bestirani2
جمعه 08 مرداد 1389, 07:11 صبح
یعنی اینکه هر بار که کاربر لوگین میشه این عمل انجام نمیشه ؟
و هر بار که کاربری لوگین میکنه تو ای پی های تکراری جستجو میشه ؟ با توجه به اینکه در پست 11 با while یه query ساختیم.
(شاید که کاربر لوگین شده ای پی ش تو بخش ای پی های غیر مشابه هستش ؟)

نه به لاگین کاربر ربط نداره

آی پی هر کاربر هم چه موقع برداشته بشه مربوط به قسمت دیگر برنامه هست
مثلاً میتوانید آی پی رو هنگام ثبت نام ثبت کنید یا با هر بار لاگین یا ...