none
רשומה רנדומאלית אבל עם עדיפות RRS feed

  • שאלה

  • היי,

    אני צריך את הדרך המהירה ביותר לקבלת רשומה עם עדיפות.

    אני צריך להציג באנרים ברוטציה כאשר יש תיעדוף לבאנרים מסויימים.

    חשבתי לשים טבלה כזאת

    id,int

    priority,int

    bannername......

    ואז לסכום את כל ה PRIORITY לפי זה לייצר מספר רנדומאלי ואז איכשהו לבחור את הרשומה שהתיעדוף שלה יושב על המספר שיצא

    כל רשומה תכיל את הסיכום של כל ה priority שמתחתיו לפי סדר של ה ID.

    הפתרון שלי נראה לי קצת בעייתי השאלה אם יש משהו יותר יעיל :) שאני לא מצליח לחשוב עליו.

    או שאני בדרך הנכונה.

    יום רביעי 08 מאי 2013 06:13

תשובות

  • למה לא להישאר כבר עם מה ששלחתי לך?

    אם אני מבין את הכוונה שלך אז הדרך שלך ממש ממש לא יעילה. אתה הולך לטחון זכרון ו IO אם בכל פעם תבנה טבלה זמנית רק בשביל להחזיר רשומה אחת אחרונה ממנה. זה יעבוד אבל זה ממש ממש אבסורד ומזכיר לי חברה שנתתי לה שירותים שביצעו

    select * from

    כי הם רצו לדעת מה הערך של ה ID האחרון בטבלה. הם העבירו לאפליקציה את כל הרשומות ואז בלולאה לקחו את האיבר האחרון.

    * אני ממליץ לך מאוד להישאר עם מה ששלחתי אם זה המצב כרכגע, כמובן תוך אינדוקס נכון של המערכת (בדוגמה אין אינדוקס כמובן אלא רק הצגת השאילתות).

    * אם תרצה ארכיטקטורה הרבה יותר מורכבת למערכת באנרים אני אוכל לפרט יותר... זה כבר יהיה דיון ארוך חדש אני מעריך. תבדוק אם אתה רוצה אפשרויות כמו שכתבתי מעל.

    * נקודה כללית: אם אתה מרגיש לא נוח לעבוד עם מספר רב של פקודותבשאילתה אחת (או יותר נכון בפנייה אחת של האפליקציה לשרת) אז תוכל לעבוד עם SP. זה גם מומלץ מסיבות אחרות. את התהליך כאן נכון יהיה להכניס ל SP ולהחזיר בסיום רק את הרשומה שבחרת רנדומלית = תוצאה סופית.


    signature

    • נערך על-ידי pituachMVP, Editor יום חמישי 09 מאי 2013 17:39
    • סומן כתשובה על-ידי tetitu שבת 11 מאי 2013 11:16
    יום חמישי 09 מאי 2013 17:38
    מנחה דיון

כל התגובות

  • הרעיון הבסיסי לא רע אבל אין צורך ב:

    "כל רשומה תכיל את הסיכום של כל ה priority שמתחתיו לפי סדר של ה ID."

    זה טור מיותר שיכול להיות מחושב בזמן אמת אחרת יש כפילות נתונים (טור מחושב הוא גם פתרון סביר)

    * יש לי מערכת ב ASP קלאסי ברובה מלפני 10 שנים כמעט שעובדת בצורה דומה (לא בדיוק... יש שם מערכת באנרים מאוד מורכבת ויעילה לניהול באנרים לפי עדיפות במיקום כזה או אחר, מספור הופעות, צפיות ועוד הרבה מאוד אפשרויות אבל הבסיס הלוגי דיי דומה). מה שהיה טוב לפני 10 שנים טוב גם היום :-) הנה דמו שלה: http://stifa.ariely.info ושם אפשר ללמוד על המקור לכינוי שלי בפורומים :-)


    signature

    יום רביעי 08 מאי 2013 07:28
    מנחה דיון
  • תודה אריאל.

    בינתיים הגעתי לזה

    DECLARE @t TABLE (NAME VARCHAR(10),score INT)
    INSERT INTO @t (name,score)
    SELECT 'banner',10 UNION ALL
    SELECT 'B',10 UNION ALL
    SELECT 'C',20 UNION ALL
    SELECT 'D',10 UNION ALL
    SELECT 'E',25 
    
    
    
    ;WITH cte AS
    (
    	SELECT name,score,ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS row
    		FROM @t
    ) 
    SELECT a.name,SUM(b.score) 
    	FROM cte a
    		INNER JOIN cte b ON a.row >=b.row
    GROUP BY a.name
    
    
    select ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 10000

    עכשיו אני רוצה לגלות איך אני מקמבן את זה ל"שאילטה" אחת  שתחזיר לי רשומה אחת

    אחרת אני כבר איישם את זה בקוד וזהו.

    -------------------------------------------

    כמובן שיש גם תאריך עליה וירידה ומיקומים וסטטיסטיקות(אומנם בסיסיות צפיה ולחיצה)

    אבל קודם מתחילים מהפשוט :)

    • נערך על-ידי tetitu יום רביעי 08 מאי 2013 07:39
    יום רביעי 08 מאי 2013 07:36
  • כמה נקודות שאמורות להוביל אותך לפתרון הסופי:

    1. היכן כל הלוגיקה שדיברת עליה? אני לא רואה שום נסיון ליישם אותה. בחלק הראשון מצאת את הסכום בצורה דינאמית אבל זה החלק הקטן (שאפשר להגיע בכמה דרכים כמו תמיד) אבל מה עם החלק של בחירת מספר רנדומלי ובחירת הרשומה המתאימה

    2. מה הקשר לשאילתה האחרונה שהיא מנותק מכל דבר?

    3. למה עשית שימוש ב

    ROW_NUMBER() OVER(ORDER BY (SELECT 1))

    מה היה הרעיון שחשבת עליו כשביצעת סידור לפי קבוע?

    4. הלוגיקה שדיברת בהתחלה היא טובה אבל אני חייב לציין שאני הלכתי בכיוון שונה לחלוטין של DDL. מה גם שאצלי היה כאמור הרבה יותר מורכבות כמו שימוש ב"חוקים" רבים לכל באנר. באנר מסויים יכול לקבל עדיפות של 20 במיקום X בעמוד P1 ועדיפות של 30 במיקום X בעמוד P1 ועדיפות 21 בעמוד P2 ועוד עדיפות 10 בכל שאר המקומות... כל זה עד שהוא מופיע X פעמים בזמן Y ואז או שהכל מתאפס או שהוא מפסיק להופיע...

    עדיין הלוגיקה הבסיסית היתה כאמור כפי שרשמת חיבור כל הסיכויים -> מציאת מספר רנדומלי בין 0 לסכום הכללי פחות 1 ולפי המספר הרנדומלי בהתאם לחוקים בוחרים את הבאנר שנמצא במיקום המתאים.

    דרך אגב! חשב מאוד להבין שיש הרבה מאוד פעולות שחוזרות על עצמן והדרך הנכונה היא לבצע אותן פעם אחת בחיי האפליקציה ולא בכל שאילתה מחדש. למשל הסכום הכללי של כל העדיפויות קבוע עד שמישהו מעדכן את אחד הבאנרים. המישהו הזה הוא מנהל המערכת ועל כל מליון כניסות של משתמשים הוא אולי מבצע שינוי אחד פעם בכמה ימים. לכן הדרך הנכונה היא להחזיק נתון זה ברמת האפליקציה! כשמישהו משנה את הנתון של אחד הבאנרים או האפליקציה מבצעת רענון אז ורק אז צריך לגשת למסד הנתונים לקחת את הנתון מחדש.

    בצורה דומה כל הלוגיקה של פיתוח אפליקציה לא בהכרח דומה ללוגיקה של כתיבת T-SQL ויש לנו חשיבות רבה לאפיון האפליקציה (כמו מתי הנתון משתנה, מתי צריך לקרוא אותו וכמה ומתי לרענן אותו)

    אם אתה רוצה "סתם" פתרון בסיס ב T-SQL אז אין בעיה אבל זו לא הדרך שאני הייתי בוחר בה. הנה שאילתה מלאה ב T-SQL, אני שם עוד כמה נתונים שיעזרו להבין מה קורה כאן, אחרי הכל זו אינה הדרך הסופית לשרת חי אלא רק דרך בסיסית ב T-SQL

    DECLARE @t TABLE (id int, NAME VARCHAR(10),score INT)
    INSERT INTO @t (id,name,score)
    SELECT 1,'banner',10 UNION ALL
    SELECT 2,'B',10 UNION ALL
    SELECT 3,'C',20 UNION ALL
    SELECT 4,'D',10 UNION ALL
    SELECT 5,'E',25 
    
    -- select * from @t
    
    declare @SumAll int
    select @SumAll = SUM(score) from @t 
    declare @MyRnd int =  rand() * @SumAll -- will bring back: 0 - (@SumAll-1)
    --select @SumAll,@MyRnd
    select *, score+ISNULL(MySum,0) as MySumScore, @MyRnd as MyRnd from (
    	select *, ISNULL((select sum(score) from @t KIn where KIn.id < KOut.id),0) as MySum from @t KOut
    ) Tbl
    where MySum <= @MyRnd and score+ISNULL(MySum,0) > @MyRnd
    -- make sure that "score" is greater then 0 ! else we need anather check in the query


    signature

    יום רביעי 08 מאי 2013 19:43
    מנחה דיון
  • הדרך שנראה לי שאני אלך

    לבצע INSERT לטבלה זמנית

    ואז עם השאילטה השניה  במקום 10000 אני אקח את MAX של הטור המחושב.

     את השימוש של

    ROW_NUMBER() OVER(ORDER BY (SELECT 1))

    עשיתי כי לא בדיוק משנה לי הסדר רק שיסכום את כל השדות שלפניו

    במידה ואני אראה שזה גורם לעומסים אז אני כבר יכניס לוגיקה חדשה ומפתיעה

    יום חמישי 09 מאי 2013 17:13
  • למה לא להישאר כבר עם מה ששלחתי לך?

    אם אני מבין את הכוונה שלך אז הדרך שלך ממש ממש לא יעילה. אתה הולך לטחון זכרון ו IO אם בכל פעם תבנה טבלה זמנית רק בשביל להחזיר רשומה אחת אחרונה ממנה. זה יעבוד אבל זה ממש ממש אבסורד ומזכיר לי חברה שנתתי לה שירותים שביצעו

    select * from

    כי הם רצו לדעת מה הערך של ה ID האחרון בטבלה. הם העבירו לאפליקציה את כל הרשומות ואז בלולאה לקחו את האיבר האחרון.

    * אני ממליץ לך מאוד להישאר עם מה ששלחתי אם זה המצב כרכגע, כמובן תוך אינדוקס נכון של המערכת (בדוגמה אין אינדוקס כמובן אלא רק הצגת השאילתות).

    * אם תרצה ארכיטקטורה הרבה יותר מורכבת למערכת באנרים אני אוכל לפרט יותר... זה כבר יהיה דיון ארוך חדש אני מעריך. תבדוק אם אתה רוצה אפשרויות כמו שכתבתי מעל.

    * נקודה כללית: אם אתה מרגיש לא נוח לעבוד עם מספר רב של פקודותבשאילתה אחת (או יותר נכון בפנייה אחת של האפליקציה לשרת) אז תוכל לעבוד עם SP. זה גם מומלץ מסיבות אחרות. את התהליך כאן נכון יהיה להכניס ל SP ולהחזיר בסיום רק את הרשומה שבחרת רנדומלית = תוצאה סופית.


    signature

    • נערך על-ידי pituachMVP, Editor יום חמישי 09 מאי 2013 17:39
    • סומן כתשובה על-ידי tetitu שבת 11 מאי 2013 11:16
    יום חמישי 09 מאי 2013 17:38
    מנחה דיון