ארכיון

Archive for דצמבר, 2009

מחיקת קבצים ישנים במערכת ההפעלה Windows

לעיתים אנו מעוניינים למחוק קבצים ישנים בספריה מסויימת או בעץ ספריות. למשל: היינו רוצים למחוק את כל הקבצים שגילם 10 ימים ויותר ואת אלה שנוצרו ב-10 הימים האחרונים היינו מעוניינים להשאיר. אבל לצערינו, אין פקודת DOS במערכת ההפעלה Windows המאפשרת מחיקה מותנית שכזו.

ישנן כמה אפשרויות לבצע את זה:

  • לכתוב סקריפט ב-VBSCRIPT
  • לכתוב סקריפט בשפה החדשה POWERSHELL.
  • לכתוב תוכנית קטנה בשפה עילית.

אני חובב סקריפטים. כשאני עובד ב-UNIX או ב- LINUX אני מוצא את עצמי כותב לא מעט סקריפטים. גם ב-Windows ניתן לכתוב סקריפטים בקלי קלות אם ב- VBSCRIPT או POWERSHELL. האחרונה מצריכה רקע בדוט נט.

במאמר זה אני רוצה להציג סקריפט שכזה שכתבתי ב-VBSCRIPT. לסקריפט יש 3 פרמטרים: שם ה-folder ממנו יש למחוק קבצים ישנים, כמה ימים מקסימום יש לשמור על הקבצים (כל השאר יש למחוק) ואופציה למחוק רק קבצים עם סיומת (extension) מסויימת. הסקריפט מוחק באופן רקורסיבי את הכל הקבצים ב-folder המצויין בפרמטר הראשון וכן את כל הקבצים הישנים שבתיקיות תחתיו.

הרי הוא לפניכם:

'
' This VB Script is responsible for deleting files in a given folder (as an external argument)
' that are older than X days.
' The script also scans files recursively in the subfolder of the given folder
'
' Written by: Lior King
'

dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim oArgs, argsCount

Set oArgs = WScript.Arguments.Unnamed
argsCount = WScript.Arguments.Unnamed.Count

dim MainFolder

If argsCount > 0 then
  set MainFolder = fso.GetFolder(oArgs(0))
End if

If argsCount = 1 then
   ProcessFolder MainFolder, 0, ""
Elseif argsCount = 2 then
   ProcessFolder MainFolder, oArgs(1), ""
ElseIf argsCount = 3 then
   ProcessFolder MainFolder, oArgs(1), oArgs(2)
Else
   WScript.Echo "Error – Missing arguments !!!"
   WScript.Echo ""
   WScript.Echo "Argument 1 – Folder name"
   WScript.Echo "Argument 2 (optional) – DaysBack to delete (Default – ignore dates)"
   WScript.Echo "Argument 3 (optional) – File extension to delete (Default – ignore extensions)."
End if

'—————
' ProcessFolder
'—————
Sub ProcessFolder (folder, DaysBack, Extension)
   On Error Resume Next
   Dim f, singlefile, SubFolders,  fileslist, ExtensionPos

   Set fileslist = folder.Files

   For Each singlefile in fileslist
      ' Check if there is an extension to the file
      ExtensionPos = InStrRev(singlefile.Name,".")
      If ExtensionPos > 0 or Len(Extension) = 0 then
   ' Check if the file's extension matches the require extension.
        if UCase(Mid(singlefile.Name, ExtensionPos+1)) = UCase(Extension) or Len(Extension) = 0 then
         if singlefile.DateLastModified < (now()-DaysBack) then
               singlefile.Delete(force)
            end if
         end if
      end if
   Next

   '
   ' Process recursively the subfolders
   '

   Set SubFolders = folder.Subfolders
   For Each f in SubFolders
     ProcessFolder f, DaysBack, Extension
   Next

End Sub

הפעלת הסקריפט לדוגמה (מתוך שורת פקודה ב-DOS), בהנחה שהסקריפט שמור בקובץ ששמו DeleteOldFiles.vbs  ואנו רוצים למחוק קבצים עם סיומת txt שגילם יותר מ-3 ימים:

cscript DeleteOldFiles.vbs  c:\myfolder 3 txt

מודעות פרסומת

שימוש בטבלאות של חתכי אוכלוסיה בבניית דו"חות

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

לצורך ההדגמה, נביא דוגמה מעולם ה-HR שבאופן מסורתי משמש בלימוד בסיסי נתונים.

נניח שיש לנו טבלת עובדים במבנה הבא (טיפוסי הנתונים הם של SQL Server אבל בקלות אפשר להמיר אותם לטיפוסים של אורקל או כל בסיס נתונים אחר):

EmpId int
EmpName varchar
DeptId int
Salary float
Bonus float

נבנה טבלת חתכי אוכלוסיה דינאמית במבנה הבא:

PopulationId int
PopulationDesc varchar
DeptId_Ind bit
DeptId_values varchar
Salary_Ind bit
Salary_From float
Salary_To float

נכניס ערכים לדוגמה בטבלה:

Salary_

To

Salary_

From

Salary_

Ind

DeptId_

values

DeptId_

Ind

Population

Desc

Population

Id

 

 

Null

1,2,5

True

Important employees

1

999999

20000

False

1,5

False

Nice employees

2

5000

0

True

10,11,12

True

Underpaid

employees

3

999999

30000

True

 

NULL

Overpaid employees

4

הגדרנו 4 חתכי אוכלוסיה. כעת נוכל ליצור דו"ח שיציג לנו את נתונים סיכומיים בכל חתך. מה בעצם מגדיר כל חתך:

  • החתך "Importance employees" מגדיר עובדים העובדים במחלקות 1 או 2 או 5.
  • החתך "Nice employees" מגדיר עובדים שלא עובדים מחלקות 1 או 5 (לא עובדים בגלל ש-DeptId_Ind הוא False) ואשר לא מרוויחים בין 20000 ו- 999999 ש"ח (לא מרוויחים בגלל ש- SalaryInd הוא False).
  • החתך "Underpaid employees" מגדיר עובדים העובדים במחלקות 10 או 11 או 12 ומשכורתם בין 0 ל- 5000 ש"ח
  • החתך "Overpaid employees" אינו מתייחס כלל למחלקות (DeptId_Ind הוא NULL) ומתייחס לעובדים המרויחים מעל 30000 ש"ח. 

לאחר שהוגדרו האוכלוסיות, צריך להציג את הנתונים. ההצגה נעשית ע"י מכפלה קרטזית של הרשומות מטבלת הנתונים employees וטבלת חיתוכי האוכלוסיה emp_population.

Select  PopulationDesc, sum(salary) "Total Sal", avg(salary) "Avg. sal", sum(bonus) "Total Bonus" 

From employees e cross join emp_population ep

 Where ((ep.DeptId IN (select word from fn_split(e.deptId, ',') f) AND ISNULL(DeptId_Ind, 1) = 1)

         OR                  

       (ep.DeptId NOT IN (select word from fn_split(e.deptId, ',') f) AND ISNULL(DeptId_Ind, 0) = 0)     

   AND 

       ((e.Salary between ep.Salary_From and ep.Salary_To AND ISNULL(Salary_Ind, 1) = 1) 

        OR

        (e.Salary NOT between ep.Salary_From and ep.Salary_To AND ISNULL(Salary_Ind, 0) = 0)        

       (( 

זהו SQL שלקוח מ-SQL Server. באותו אופן אפשר להתאימו לאורקל ולהחליף את הפונקציה ISNULL ב-NVL.

שימו לב לפונקציה fn_split שאמורה להפוך מחרוזת מופרדת בפסיקים (או תו מפריד אחר) לטבלת ערכים. פונקציה כזו אפשר להוריד ממגוון אתרים כמו למשל:http://www.sqlservercentral.com/scripts/Miscellaneous/31913

באורקל מדובר ב-pipelined function ולכן הקריאה לפונקציה תהיה יחד עם שימוש בפונקציה table. דוגמה לפונקציה שכזו באורקל אפשר להוריד מהבלוג הזה:http://edgewaters.blogspot.com/2008/10/oracle-plsql-split-function-boosts.html

 דוגמה לפלט אפשרי:

Population Desc Total Sal Avg. Sal Total Bonus
Important Employees 100000 22000 280000
Nice Employees 120000 15000 100000
Under Paid employees 150000 3000 0
Over Paid employees 1000000 42000 700000

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

 

"עכשיו מעונן" – בסיסי נתונים במחשוב ענן

מחשוב ענן (Cloud computing) הוא buzzword שרץ חזק בשנתיים האחרונות בעולם ה-IT. חברות מובילות כמו מיקרוסופט, אורקל ו-IBM עובדות על כל מיני פתרונות בתחום וכבר נשפכו לא מעט מילים על כך (והרבה מאד דולרים).

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

דמיינו לכם שאתם מפתחים מערכת שה-DB שלה בתוך ענן, אי שם ברשת ה-WAN (או ה-LAN הארגוני). לא צריך שום התקנות, שום ברזלים, וה-DB הזה מנוהל ומתוחזק ע"י מישהו אחר, עובר גיבוי ע"י מישהו אחר, ניתן להעמיס עליו כמות משתמשים ככל שנדרש מבלי לדאוג ל"ברזלים" (מישהו אחר דואג לזה). אתה משלם על השימוש ב-DB בהתאם למשאבים שאתה באמת צורך. אה ! מה עם storage? את מי זה מעניין. מישהו אחר דואג ל-storage. פשוט משלמים על פי מה שצורכים. ועוד משהו: ה-DB הזה זמין 24X7 וכמעט שלעולם לא נופל (כי הוא מתוחזק ע"י טכנולוגיות clustering למיניהן).

נשמע מעניין, נכון?

בואו ניקח עוד צעד קדימה. היום ישנו "פיצוץ" של בסיסי נתונים. בארגונים גדולים ישנם אלפי בסיסי נתונים ולעיתים גם צריך לחבר ביניהם. אפליקציות צריכות להתחבר לפעמים לכמה בסיסי נתונים במקביל והמפתחים מסתבכים עם התשתיות, הגדרות, אבטחת מידע ושאר ירקות. למה זה גורם? זה גורם להשקעות אדירות של תקציב בהקמת צוותי IT שיתחזקו את כל השרתים, את ה-storage ואת בסיסי הנתונים שרק מתרבים ומתנפחים.

מחשוב ענן יכול להיות ברשת האינטרנט העולמית או פנימי באינטראנט הארגוני.

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

אבל השוס הגדול יהיה להערכתי בארגונים הגדולים. ארגון שיקים לו "ענן" ארגוני משלו, יוכל לספק למחלקות השונות סביבה נוחה להקמת מערכות בלי כאב הראש של טיפול בתשתיות.

מיקרוסופט הולכת עם פרויקט שאפתני בשם Azure כאשר חלק ממנו הוא ה-SQL Azure שהוא למעשה פתרון לבסיס נתונים במחשוב ענן אשר צפוי להיות זמין לשימוש דרך האינטרנט במהלך השנה הקרובה. לפרטים:  http://www.microsoft.com/windowsazure/sqlazure

אורקל גם היא עובדת חזק על ה"ענן" וחברה לחברת "אמזון" (כן, אלה מהספרים…) ומאפשרת לשים פתרון תוכנה שלם מבוסס אורקל בענן של אמזון. כמו כן ניתן לגבות DB מחוץ לענן אל תוך הענן. לפרטים: http://www.oracle.com/technology/tech/cloud/index.html

עדיין אין פתרון מוכרז ל"ענן" ארגוני – אבל בטח גם זה יגיע בהמשך.

בשורה התחתונה, אנחנו על סף עידן חדש בתחום בסיסי הנתונים. עידן ה"ענן" עשוי לחדור כבר ב-2010 חזק לתעשייה. האם זה אומר שבסיסי הנתונים "הרגילים" ייעלמו בעתיד? התשובה: לא כל כך מהר! אנחנו צפויים לראות מערכות "ענן" רצות לצד מערכות קונוונציונליות לפחות בשנים הקרובות. ומה בעתיד הרחוק יותר? התשובה תלויה כנראה ב-buzzwords של 2015.

משתמשים ב-XMLType של אורקל? כדאי שתקראו את זה

XMLType הוא טיפוס נתונים ותיק עוד מימי אורקל 8i. לרוב אנחנו צריכים לאנדקס ערכים מתוך ה-XML שיכולים להופיע ב-elements או ב-attributes שבתוך ה-XML. שימוש שכיח לכך הוא ע"י הרכבת אינדקס על פונקציה המבצעת קריאה ל-ExtractValue באופן הבא:

CREATE INDEX emp_id_ix ON employees

  (extractValue(XMLCol, '/Employees/Id'));

 

אבל מה יקרה אם ה-XML מכיל מס' אלמנטים בעלי אותו שם באותה רמה בעץ? לדוגמה:

<Employees>

            <Id> 123</Id>

            <Id> 234</Id>

</Employees>

אם ננסה ליצור את האינדקס על  ה-XML שבדוגמה נקבל שגיאה:

ORA-19025: EXTRACTVALUE returns value of only one node

הסיבה לשגיאה היא ש-ExtractValue לא יכול להחזיר יותר מערך אחד. אז מה עושים?

האמת – אני לא ממש מוצא פתרון אינטואיטיבי לזה. אשמח לקבל תגובות מאנשים לגבי פתרונות פשוטים.

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

דוגמה:

נניח שיש לי טבלה עם עמודה XML שנקראת xmltab:

create table xmltab (xmlid int, xmlcol xmltype );

ניצור "טבלת בת" שתכיל את הערכים שנוציא החוצה מה-XML:

create table xmltab_Vals (id int, xmlid int, val int);

create sequence xmltab_vals_id start with 1;

כעת, ניצור טריגר שיזין את טבלת הבת באופן אוטומטי ע"י הוצאת הערכים מה-XML

CREATE OR REPLACE
TRIGGER TR_XMLTAB
AFTER INSERT ON XMLTAB
REFERENCING OLD AS oldval NEW AS newval
FOR EACH ROW 
BEGIN
  insert into xmltab_Vals
    SELECT xmltab_vals_id.nextval, :newval.id, extractvalue(value(d),'/id')
      FROM table(xmlsequence(
                 extract(:newval.xmlcol ,'/employees/id'))) d;

END;

ה-select שבטריגר הופך את הערכים של האלמנט Id לטבלה שמכילה קטעי XML עבור כל Id בנפרד. בשלב הבא, נעשה ExtractValue כדי לחלץ את ה-Id. הפעם לא נקבל את השגיאה ORA-19025 והערכים יסתדרו להם יפה בתוך הטבלה xmltab_Vals.

אם נזין את ה-XML שהבאתי כדוגמה, נקבל שתי רשומות בטבלת xmltab_vals עם הערכים 123 ו-234.

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

כמובן שכדאי ליצור fk עם on delete cascade בין הטבלאות הנ"ל ויש לכוון את השאילתות מול טבלת הבת במקום להשתמש ב-extractValue.

אשמח לשמוע רעיונות נוספים.

לאסוף מדדים ממערכת ההפעלה Windows ולתחקר אותם בהמשך

Perfmon הוא כלי נפלא ופשוט המאפשר לראות מדדי מערכת. אבל – לעיתים אנו רוצים לדגום יום שלם או שבוע שלם של מדדים שמייצר שרת Windows ואח"כ לנתח את הנתונים. כמו למשל, מתי היו רגעי שיא של פעולות CPU, רגעי שיא או שפל של תור הפניות ל-I/O  משכי זמן של Peaks וכו'.

ישנן שתי דרכים לעשות זאת:

דרך אחת – להשתמש ב-Utility של Windows הנקראת LOGMAN.

דרך שניה – לבצע "שאילתות" למשאבי השרת באמצעות אובייקטים של WMI או Windows Management Instrumentation. במקרה זה אפשר להשתמש ב-VBScript או לכתוב תוכנית בשפה עילית (DOT NET או Unmanaged code).

במאמר הזה אתמקד בשימוש ב-LOGMAN. שימוש ב-WMI הוא נושא למאמר נפרד ואולי אפילו לכמה מאמרים. נשאיר את זה בצד לעת עתה.

LOGMAN היא תוכנית שירות שבאה בכל גרסאות WINDOWS והיא מאפשרת דגימות של מדדי המערכת בדומה ל-PerfMon. שלא כמו PerfMon, תוכנית LOGMAN רצה ברקע ללא ממשק משתמש ובכך היא מהווה נטל מינימלי ביותר על השרת. LOGMAN יכולה לדגום את השרת במרווחי זמן קבועים שניתן לקבוע לה (כל שנייה זה המינימום של הדגימה) והיא יכולה להזין את המדדים לקובץ או אפילו ל-DB רלציוני. אפשר אפילו להפעיל את כריית המדדים על שרת אחר ברשת.

ב-Books On Line (או BOL) של מיקרוסופט אפשר למצוא תיעוד של כל שלל האפשרויות לשימוש בתוכנה זו.

כדי ללמוד איך להשתמש ב-LOGMAN, בואו פשוט נראה דוגמה. בחלון שורת פקודה (CMD) נבצע את הפקודה הבאה:

logman create counter MyTrace -s MyServer -f  sql -si "00:00:05" –v -o DBServer!DBA -cf "c:\counters.config" -u MyUsername MyPassword

בפקודה זו הגדרנו תהליך איסוף מדדים בשם MyTrace שדוגם מדדים משרת בשם MyServer כל 5 שניות ואת התוצאות אנחנו רוצים להזין לטבלה ב-DB רלציוני התומך ODBC. הנתונים יכנסו לשרת DB בשם DBServer  לבסיס נתונים הנקרא DBA (באורקל זאת תהיה סכימה בשם DBA). ה-LOGIN לבסיס הנתונים יהיה עם המשתמש MyUsername ועם הסיסמה MyPassword. המדדים שברצוננו לדגום מפורטים בקובץ בשם counters.config.

כדי העסק יעבוד, יש להגדיר את ה-DB שאליו יש להזין את המדדים ב- ODBC Data Sources (ע"י Control Panel -> Administrative tools -> Data Sources). בלשונית SYSTEM DSN הוסיפו את שרת בסיס הנתונים (יכול להיות SQL Server, אורקל, MySQL או כל בסיס נתונים אחר שתומך ODBC).

LOGMAN יצור באופן אוטומטי טבלה (אם היא לא קיימת) שאליה הוא יזין את המדדים.

את רשימת המדדים אפשר לבנות בקלות ע"י PerfMon. אספו את המדדים שברצונכם לדגום עם LOGMAN באמצעות PerfMon. אח"כ לחצו CTRL-L ויפתח חלון. בלשונית DATA תוכלו לראות את שמות המדדים שבחרתם כפי שיש לציינם בקובץ הקונפיגורציה. אפשר כמובן לציין לא רק מדדים של Windows אלא גם מדדים של SQL Server או אורקל.

לאחר שהגדרנו את תהליך איסוף המדדים, כל שנותר הוא להפעיל אותו ע"י הפקודה:

logman start -s MyServer MyTrace

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

כדי לעצור את התהליך אפשר להריץ:

logman stop -s MyServer MyTrace

התהליך נעצר. ניתן לשוב ולהפעילו ע"י START.