ต้องการคำแนะนำเกี่ยวกับวิธีที่ดีที่สุดในการกรองไฟล์ข้อความตามตารางอ้างอิง

ขณะนี้ฉันกำลังมองหาวิธีเพิ่มประสิทธิภาพกระบวนการที่
ใช้เวลานานในการทำงาน

  • มีไฟล์ข้อความประมาณ 270 ไฟล์ที่ต้องกรอง
  • แต่ละไฟล์มีประมาณ 70,000 ~ 150,000 บรรทัด
  • ตารางอ้างอิงมักจะมีบันทึกประมาณ 16 ล้าน ภายใต้ Oracle 10g
  • กระบวนการนี้ดำเนินการทุกชั่วโมง
  • มีความเป็นไปได้ที่ 9 อินสแตนซ์ของกระบวนการนั้นอาจจะทำงานเกือบ
    พร้อมกัน

สิ่งที่ฉันทำในขณะนี้คือสปูลตารางอ้างอิงลงในไฟล์ คัดลอกสิ่งนั้นลงใน
แฮช ทำแบบเดียวกันกับไฟล์ข้อความ จากนั้นจับคู่แฮชคีย์
บันทึกใดๆ ในไฟล์ข้อความที่พบใน รายการอ้างอิงจะถูกยกเลิก

สิ่งนี้จะเกิดขึ้นซ้ำสำหรับไฟล์ทั้งหมด 270 ไฟล์ อย่างไรก็ตาม ส่วนสพูลจะทำ
เพียงครั้งเดียวในตอนเริ่มต้น

อย่างไรก็ตาม วิธีการนี้ใช้ RAM ประมาณ 300mb~500mb และด้วย
ความเป็นไปได้ที่จะมีอินสแตนซ์หลายอินสแตนซ์ของกระบวนการนั้นทำงานเกือบ
ในเวลาเดียวกัน ถือเป็นฝันร้ายสำหรับเซิร์ฟเวอร์ของเรา

มีความคิดใดที่จะดำเนินการให้ดีขึ้นกว่านี้?


person cr8ivecodesmith    schedule 24.02.2012    source แหล่งที่มา


คำตอบ (2)


ฉันขอแนะนำให้คุณโหลดข้อมูล DB ลงในหน่วยความจำเท่านั้น และประมวลผลไฟล์เช่น (ขออภัย นั่นเป็นรหัสเทียม แต่คุณควรมีแนวคิดและนำไปใช้ใน Perl):

HashSet dbData = GetDataFromDB();
foreach(filename in filenames) {
    FileHandle handle = OpenRead(filename);
    FileHandle tmphandle = OpenWrite(filename + ".tmp");
    while(string line = handle.ReadLine()) {
        if(!dbData.Contains(line)) {
            tmphandle.Write(line);
        }
    }
    tmphandle.Flush();
    tmphandle.Close();
    handle.Close();
    Delete(filename);
    Rename(tmpfilename, filename);
}

นี่จะใช้ RAM มากเท่าที่ตารางอ้างอิงของคุณใช้เท่านั้น

person penartur    schedule 24.02.2012

ดูเหมือนว่าบางสิ่งที่สามารถทำได้อย่างมีประสิทธิภาพในฐานข้อมูล (การต่อต้านการเข้าร่วมครั้งใหญ่)

คุณสามารถใช้ UTL_FILE เพื่ออ่านไฟล์และ เปรียบเทียบโดยตรงกับตารางอ้างอิงของคุณ คุณสามารถใช้ฟังก์ชัน wrapper เพื่อเลือกไฟล์ของคุณโดยตรง:

CREATE OR REPLACE TYPE tab_varchar AS TABLE OF VARCHAR2(4000);
/

CREATE OR REPLACE FUNCTION select_file(p_dir VARCHAR2, p_file VARCHAR2)
   RETURN tab_varchar
   PIPELINED IS
   l_file utl_file.file_type := utl_file.fopen(p_dir, p_file, 'r', 4000);
   l_line VARCHAR2(4000);
BEGIN
   LOOP
      BEGIN
         utl_file.get_line(l_file, l_line);
      EXCEPTION
         WHEN No_Data_Found THEN
            EXIT;
      END;
      PIPE ROW (l_line);
   END LOOP;
   utl_file.fclose(l_file);
   RETURN;
END;
/

ซึ่งจะทำให้คุณสามารถเลือกข้อมูลของคุณได้โดยตรง ตัวอย่างเช่น จะส่งคืนเนื้อหาของไฟล์ C:\tmp\a.txt

create directory tmp_dir as 'C:\tmp\';

select column_value from table(select_file('TMP_DIR', 'a.txt'));

จากที่นี่ ข้อความค้นหาเดียวควรจะใช้ได้สำหรับแต่ละไฟล์ เช่น:

INSERT INTO ref_table r
   (SELECT column_value
      FROM table(select_file(:dir, :file_name)
     WHERE column_value NOT IN (SELECT ref_value
                                  FROM ref_table
                                 WHERE ref_value IS NOT NULL)
       AND column_value IS NOT NULL);
person Vincent Malgrat    schedule 24.02.2012