[solved] Πρόβλημα με εισαγωγή δεδομένων

Σε αυτή την περιοχή μπορείτε να βρείτε ή να αναζητήσετε πληροφορίες σχετικές με την PHP

Συντονιστές: WebDev Moderators, Super-Moderators, PHP Moderators

Απάντηση
Apostolis_38
Δημοσιεύσεις: 1969
Εγγραφή: 14 Φεβ 2008 16:20
Τοποθεσία: ΠΕΙΡΑΙΑΣ

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από Apostolis_38 » 20 Νοέμ 2010 09:53

Καλημέρα σε όλους.

Υπάρχει το εξής πρόβλημα:
- Στην αρχή δημιουργείται ένας tmp πίνακας (ακριβώς ίδιος με άλλον πίνακα) με την εντολή create table like και καταχωρούνται δεδομένα με load data infile από αρχείο το οποίο γίνεται upload.
- Επειτα αντιπαραβάλονται οι εγγραφές ενός πίνακα με τις εγγγραφές του tmp πίνακα με ένα select join.
Αν ο "κανονικός" πίνακας είναι άδειος ή δεν υπάρχουν ίδιες εγγραφές στους δύο πίνακες τα δεδομένα καταχωρούνται στον πίνακα χωρίς πρόβλημα.
Αν όμως βρεθούν κοινές εγγραφές, τότε αυτές οι εγγραφές του "κανονικού" πίνακα διαγράφονται και με insert into table select * from tmp_table περνιούνται αυτές που υπάρχουν στον tmp. Οι καινούργιες δηλαδή εγγραφές.

Το πρόβλημα είναι εδώ ακριβώς γιατί οτι οι νέες εγγραφές που πάνε να περαστούν μπορεί να είναι κάποιες χιλιάδες.
Με αποτέλεσμα το πρόγραμμα να ζορίζεται πολύ, ακόμα και να "σκάει" μερικές φορές.
Η βλακεία της υπόθεσης είναι οτι αυτό μπορεί να γίνει ακόμα και για 2-3 νέες εγγραφές μόνο...

Καμμιά ιδέα για να τρέχει πιο γρήγορα το insert into table select * from;
Τα lock tables,high priority κ.λ.π. κ.λ.π. δεν έχουνε σχεδόν καμμία επίδραση.
Ακόμα και η αύξηση του max_execution_time δεν λύνει το πρόβλημα.
Και το κακό είναι οτι αν εκείνη τη στιγμή τύχει και "βλεπουν" τα data άλλοι χρήστες το πρόβλημα θα επιδεινωθεί.

Υ.Γ. Η λογική είναι οτι θα πρέπει να γίνονται update μόνο οι διαφορετικές εγγραφές αλλά η οδηγία είναι οτι "πρέπει" να γίνει με τον τρόπο που ανέφερα. Γι αυτό ψάχνω να βρω κάποια εναλλακτική λύση μήπως μπορεί να γίνει έτσι.
Τελευταία επεξεργασία από το μέλος Apostolis_38 την 23 Νοέμ 2010 08:17, έχει επεξεργασθεί 1 φορά συνολικά.

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από gvre » 20 Νοέμ 2010 11:43

Αν μιλάμε για MySQL και το πρόβλημα που αναφέρεις δε λύνεται με triggers, δοκίμασε μέσα σε ένα transaction να κάνεις τα INSERTs με το INSERT ... ON DUPLICATE KEY UPDATE.

Apostolis_38
Δημοσιεύσεις: 1969
Εγγραφή: 14 Φεβ 2008 16:20
Τοποθεσία: ΠΕΙΡΑΙΑΣ

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από Apostolis_38 » 20 Νοέμ 2010 12:01

Ναι για MySQL μιλάμε.

Στην δεύτερη περίπτωση, αν κατάλαβα καλά, μιλάμε για εγγραφή "επάνω" στις ήδη υπάρχουσες αντί για delete και μετά insert.
Κάτι τέτοιο λες;

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από gvre » 20 Νοέμ 2010 12:07

Ναι. Αν το INSERT αποτύχει λόγω duplicate value στο πρωτεύων κλειδί ή σε unique index τότε θα κάνει UPDATE την παλιά εγγραφή με τις νέες τιμές που θα του δώσεις. Όλα αυτά κάνε τα μέσα στο ίδιο transaction. Πριν από αυτό όμως δες αν μπορείς να λύσεις το πρόβλημά σου με triggers.

Apostolis_38
Δημοσιεύσεις: 1969
Εγγραφή: 14 Φεβ 2008 16:20
Τοποθεσία: ΠΕΙΡΑΙΑΣ

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από Apostolis_38 » 20 Νοέμ 2010 15:50

Με trigger σε απόλυτους αριθμούς βελτιώθηκε κάπως η κατάσταση αλλά δεν έγινε και τίποτα σπουδαίο.

Με τις πολλές δοκιμές όμως ανακάλυψα οτι το πρόβλημα είναι μάλλον αλλού.
Στο αρχείο που γίνεται upload.

Γίνεται το εξής:
Γίνεται upload το αρχείο και γίνετε μετατροπή στα δεδομένα του γιατί το αρχείο προέρχεται από custom εφαμογή (σε στυλ excel).

Κώδικας: Επιλογή όλων

//---OPEN AND GET CONTENTS OF FILE
file_put_contents($read, iconv('cp1253', 'UTF-8',	file_get_contents($read) ) );
Μετά γίνεται η δημιουργία του tmp και η εισαγωγή των δεδομένων:

Κώδικας: Επιλογή όλων

//---CREATE *_tmp TABLE
$query1_1 = "CREATE TABLE ".$t."_tmp LIKE ".$t." ";
$result1_1 = mysql_query($query1_1);

//---LOAD DATA FROM UPLOADED FILE INTO *_tmp TABLE
$query1_2 = "LOAD DATA INFILE '".$read."' 
INTO TABLE ".$t."_tmp 
FIELDS TERMINATED BY ',' 
ENCLOSED BY '\"'
LINES TERMINATED BY '\\n' ";
Την πρώτη φορά που περνιούνται τα δεδομένα εισάγονται ολόσωστα.
Την επόμενη φορά (ακόμα κι όταν πάμε να περάσουμε το ίδιο αρχείο και χωρίς να αλλάξει τίποτα απολύτως στο script) η κωδικοποίηση των Ελληνικών χαρακτήρων γίνεται μαντάρα.
Ετσι το query βρίσκει invalid character και προσπαθεί να περάσει εγγραφές.
Αλλες φορές τα καταφέρνει (μετά από πολύ ώρα και φυσικά με τους Ελληνικούς χαρακτήρες μπάχαλο) κι άλλες "σκάει" και πετάει μήνυμα για invalid character.



Τι σκ@t@ :evil: :evil: :evil: :evil: :evil: :evil:

Άβαταρ μέλους
fafos
Script Master
Δημοσιεύσεις: 6231
Εγγραφή: 30 Νοέμ 2004 03:09

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από fafos » 20 Νοέμ 2010 16:00

gia to zorizma xrhsimopoihse thn sleep()
Οι πάνες και οι πολιτικοί πρέπει να αλλάζονται συχνά για τον ίδιο λόγο...

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από gvre » 20 Νοέμ 2010 16:02

Από ότι κατάλαβα, κάθε φορά ανεβάζεις νέο αρχείο, το εισάγεις σε ένα temp πίνακα και μετά κάνεις το update του κανονικού πίνακα από τον temp. Υποθέτω ότι το trigger το έβαλες στον temp.

Κώδικας: Επιλογή όλων

/---OPEN AND GET CONTENTS OF FILE 
file_put_contents($read, iconv('cp1253', 'UTF-8',   file_get_contents($read) ) ); 
Αυτό κάνε το μέσα από το shell με iconv -f CP1253 -t UTF-8 < input_file > output_file τη στιγμή που κάνεις το upload.
Την επόμενη φορά (ακόμα κι όταν πάμε να περάσουμε το ίδιο αρχείο και χωρίς να αλλάξει τίποτα απολύτως στο script) η κωδικοποίηση των Ελληνικών χαρακτήρων γίνεται μαντάρα.
Λογικό αφού τη δεύτερη φορά το αρχείο είναι ήδη σε utf8 encoding.

Apostolis_38
Δημοσιεύσεις: 1969
Εγγραφή: 14 Φεβ 2008 16:20
Τοποθεσία: ΠΕΙΡΑΙΑΣ

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από Apostolis_38 » 20 Νοέμ 2010 17:02

Λοιπόν, ορίστε όλα τα βήματα γιατί θα φρικάρω :evil:

1. γίνετε το upload και η μετατροπή της κωδικοποίησης

Κώδικας: Επιλογή όλων

//---OPEN AND GET CONTENTS OF FILE
file_put_contents&#40;$read, iconv&#40;'cp1253', 'UTF-8',	file_get_contents&#40;$read&#41; &#41; &#41;;
2. Διαγράφετε καλού κακού ο tmp μήπως έχει ξεμείνει από πρίν και δημιουργείται ο κανούργιος

Κώδικας: Επιλογή όλων

//---DROP *_tmp TABLE IN CASE IT EXISTS
$query1 = "DROP TABLE ".$t."_tmp";
$result1 = mysql_query&#40;$query1&#41;;
//---CREATE *_tmp TABLE
$query1_1 = "CREATE TABLE ".$t."_tmp LIKE ".$t." ";
$result1_1 = mysql_query&#40;$query1_1&#41;;
3. Εισάγονται τα δεδομένα στον tmp (καλού κακού έχω βάλει πάλι το set names)

Κώδικας: Επιλογή όλων

//---LOAD DATA FROM UPLOADED FILE INTO *_tmp TABLE
$query1_2 = "LOAD DATA INFILE '".$read."' 
INTO TABLE ".$t."_tmp 
FIELDS TERMINATED BY ',' 
ENCLOSED BY '\"'
LINES TERMINATED BY '\\n' ";
mysql_query&#40;"SET NAMES 'utf8'"&#41;;
mysql_query&#40;"SET CHARACTER SET 'utf8'"&#41;;
mysql_query&#40;$query1_2&#41;;
4. Καλώ το αρχείο που κάνει τους ελέγχους.

Κώδικας: Επιλογή όλων

include &#40;"import_checks.php"&#41;;
switch&#40;$t&#41;	&#123;
case &#40;$t == "stoxemp"&#41;&#58;
new CheckStoxemp&#40;&#41;;
break;
&#125;
5. Αναζήτηση για όμοιες εγγραφές

Κώδικας: Επιλογή όλων

//---SELECT FROM TABLE stoxemp
$query1_1 = "SELECT stoxemp.stoh_apo,stoxemp.stoh_eos 
FROM stoxemp 
INNER JOIN stoxemp_tmp 
ON stoxemp.stoh_apo = stoxemp_tmp.stoh_apo 
AND stoxemp.stoh_eos = stoxemp_tmp.stoh_eos 
AND stoxemp.trimino = stoxemp_tmp.trimino 
ORDER BY stoxemp.stoh_apo";
$result1_1 = mysql_query&#40;$query1_1&#41;;
$num_results1_1 = mysql_num_rows&#40;$result1_1&#41;;
6. Αν βρεθούν εμφανίζεται μήνυμα και ο χρήστης επιλέγει αν θα εισάγει τις νέες τιμές ή όχι.
Εστω πως λέει ναι. Διαγράφονται οι παλιές εγγραφές και περνιούνται οι νέες.

Κώδικας: Επιλογή όλων

//---IF USER CHOOSES TO PROCEED DELETE DATA FROM stoxemp
while &#40;$row = mysql_fetch_assoc&#40;$result1_1&#41; &#41;	&#123;
$query1_2 = "DELETE FROM stoxemp 
WHERE CONCAT&#40;trim&#40;stoh_apo&#41;,trim&#40;stoh_eos&#41;&#41; = '".trim &#40;$row&#91;"stoh_apo"&#93;&#41;.trim &#40;$row&#91;"stoh_eos"&#93;&#41;."' ";
//---CLOSE while &#40;$row = mysql_fetch_assoc&#40;$result1_1&#41; &#41; LOOP
&#125;
//---INSERT DATA FROM stoxemp_tmp INTO stoxemp
$query1_3 = "INSERT INTO stoxemp 
SELECT * FROM stoxemp_tmp";
Αλλιώς αν δεν υπάρχουν όμοιες εγγραφές περνάει αμέσως τα δεδομένα.

Κώδικας: Επιλογή όλων

//---INSERT DATA FROM stoxemp_tmp INTO stoxemp
$query1_3 = "INSERT INTO stoxemp 
SELECT * FROM stoxemp_tmp";
Μέσα σε όλο αυτά λοιπόν, όταν ο "κανονικός" πίνακας δεν έχει εγγραφές ή δεν υπάρχουν όμοιες εγγραφές όλα περνιούνται μια χαρά.

Αν υπάρχουν δημιουργείται το πρόβλημα.

@gvre:
- Ναι, αλλά το trigger μπήκε $query1_3 = "INSERT INTO stoxemp
SELECT * FROM stoxemp_tmp";
Εκεί είναι το ζόρι.
- Με μπέρδεψες. shell εννοείς το mysql shell;
- Οχι, το αρχείο γίνεται upload (έστω από το desktop) και αποθηκεύεται σε folder στην εφαρμογή. Το δεύτερο αρχείο είναι στο οποίο γίνεται η μετατροπή με το iconv.
Οταν κάνω πάλι upload το πρώτο αρχείο (από το desktop) ξεκινάει η διαδικασία από την αρχή αλλά δημιουργείται το σφάλμα με την κωδικοποίηση.

@fafos: Κι άλλη καθυστέρηση; Τι θα κερδίσω;
Με μπέρδεψες.

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από gvre » 20 Νοέμ 2010 17:50

1. Χρειάζεσαι απαραίτητα τον πίνακα tmp ή δεν έχεις πρόβλημα να κάνεις update απευθείας τον αρχικό πίνακα;
2. Πως ακριβώς φορτώνεις το αρχείο;
3. Πόσες εγγραφές συνολικά περιέχει (στο περίπου);
4. Πόσο % των εγγραφών έχει αλλάξει σε κάθε νέο αρχείο (στο περίπου);

Apostolis_38
Δημοσιεύσεις: 1969
Εγγραφή: 14 Φεβ 2008 16:20
Τοποθεσία: ΠΕΙΡΑΙΑΣ

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από Apostolis_38 » 20 Νοέμ 2010 18:43

gvre έγραψε:1. Χρειάζεσαι απαραίτητα τον πίνακα tmp ή δεν έχεις πρόβλημα να κάνεις update απευθείας τον αρχικό πίνακα;
Οχι απαραίτητα αλλά μου φαίνεται πιο δύσκολο να γίνει ο έλεγχος για τις όμοιες εγγραφές μεταξύ του πίνακα και του αρχείου.
Και λιγότερο αξιόπιστο.
gvre έγραψε:2. Πως ακριβώς φορτώνεις το αρχείο;
Το κάνω upload με τη γνωστή φόρμα σε ένα folder μέσα στην εφαρμογή

Κώδικας: Επιλογή όλων

$uploaddir = $_SERVER&#91;'DOCUMENT_ROOT'&#93;."/uploads/";
με header location πηγαίνω στο αρχείο που κάνει το load data infile

Κώδικας: Επιλογή όλων

header &#40;"Location&#58;import.php?file=".$file."&t=".$t.""&#41;;
το ανοίγω

Κώδικας: Επιλογή όλων

//---DECLARE VARIABLES
	$read = $_GET&#91;"file"&#93;;
	$t =  $_GET&#91;"t"&#93;;

//---OPEN AND GET CONTENTS OF FILE
		file_put_contents&#40;$read, iconv&#40;'cp1253', 'UTF-8',	file_get_contents&#40;$read&#41; &#41; &#41;;
κ.λ.π κ.λ.π.
gvre έγραψε:3. Πόσες εγγραφές συνολικά περιέχει (στο περίπου);
4.000+
gvre έγραψε:4. Πόσο % των εγγραφών έχει αλλάξει σε κάθε νέο αρχείο (στο περίπου);
Αγνωστο.

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από gvre » 20 Νοέμ 2010 19:18

Μπορείς να παρακάμψεις τον tmp πίνακα και να κάνεις τα εξής:

1. Προσθέτεις στον πίνακα $t ένα επιπλέον πεδίο checksum το οποίο θα είναι πχ ένα md5 όλων των υπόλοιπων πεδίων των οποίων η τιμή μπορεί να μεταβληθεί (το primary key το αφήνεις έξω).
2. Μόλις ανεβάσεις το αρχείο θα εκτελέσεις τον παρακάτω κώδικα για να μετατρέψεις το αρχείο σε UTF-8.

Κώδικας: Επιλογή όλων

$dest = "_temp_";
$out  = array&#40;&#41;;
exec&#40;"iconv -f CP1253 -t UTF-8 " . escapeshellarg&#40;$read&#41; . " -o $dest && mv $dest " . escapeshellarg&#40;$read&#41;, $out, $ret&#41;; 
if &#40;$ret != 0&#41;
&#123;
        die&#40;"Error while converting. Aborting with error '$ret'."&#41;; // Replace with better error handling
&#125;
3. Ανοίγεις το αρχείο με fopen και διαβάζεις μια μια γραμμή (όχι με file ή file_get_contents).
4. Ξεκινάς ένα transaction.
5. Για κάθε γραμμή που διαβάζεις φτιάχνεις το αντίστοιχο checksum και ελέγχεις αν η εγγραφή στη βάση σου έχει το ίδιο ή διαφορετικό. Αν είναι διαφορετικό κάνεις update την εγγραφή (αν δεν υπάρχει η εγγραφή στη βάση, κάνεις INSERT).
6. Κάνεις commit το transaction.
7. Κλείνεις το αρχείο με fclose.

Δοκίμασέ το και πες αν έχει διαφορά στο χρόνο εκτέλεσης.

ps. Υποθέτω ότι υπάρχουν τα απαραίτητα indexes στον πίνακα. Αν μπορείς, στείλε και ένα output από την SHOW CREATE TABLE πινακας

Apostolis_38
Δημοσιεύσεις: 1969
Εγγραφή: 14 Φεβ 2008 16:20
Τοποθεσία: ΠΕΙΡΑΙΑΣ

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από Apostolis_38 » 20 Νοέμ 2010 19:43

Αν εξαρτιόταν από μένα πολλά θα μπορούσα να κάνω...
Η δομή του πίνακα και η διαδικασία δεν μπορούν να αλλάξουν.

Παρ' όλα αυτά το πρόβλημα που σκάει είναι κουφό.

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από gvre » 20 Νοέμ 2010 20:23

Μήπως τη 2η φορά προσπαθεί να περάσει από την iconv το παλιό αρχείο; Το όνομα του αρχείου που περνάς στην iconv είναι πάντα το ίδιο ή αλλάζει;

Apostolis_38
Δημοσιεύσεις: 1969
Εγγραφή: 14 Φεβ 2008 16:20
Τοποθεσία: ΠΕΙΡΑΙΑΣ

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από Apostolis_38 » 20 Νοέμ 2010 20:51

Είτε αλλάζει είτε παραμένει το ίδιο αρχείο το πρόβλημα δημιουργείται.
Κάτι μυστήριο συμβαίνει.

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

[solved] Πρόβλημα με εισαγωγή δεδομένων

Δημοσίευση από gvre » 20 Νοέμ 2010 21:09

Αν μπορείς, στείλε το script του upload και ένα sample data file (εδώ ή με pm).

Απάντηση

Επιστροφή στο “PHP Προγραμματισμός”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 0 επισκέπτες