How to Update 1 Million of rows quickly in MYSQL [duplicate] - php

This question already has answers here:
Best way to INSERT many values in mysqli?
(4 answers)
Closed 1 year ago.
I have only 1 table with 1 million rows that i need to update. The data what I need to update is in a file.txt and its only 1 value to update in 1 million rows.
I use PHP to read file and make the Update.
The problem is the time. Is so slow. Any idea to improve and make more fast?
What I have is:
UPDATE productos SET urlRedirect = getChangeProducto WHERE url LIKE 'getUrlProducto'
TXT file, 2 values separated by (;) first are getChangeProducto and second getUrlProducto:
https://www.example.com/guess/8595651?o=34&t=direct&f=102.301&ord=111;https://example.com/p/guess-jeans-116-175-cm-327554`
PHP FILE:
$mysqli = get_dbc();
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: (".$mysqli->connect_errno.") ".$mysqli->connect_error;
exit();
}
$mysqli->set_charset("utf8");
if (!$mysqli) exit(mysqli_connect_error());
$handle = fopen("fileToUpdate.txt", "r");
$total_lines = 0;
if ($handle) {
$line = fgets($handle);
while ($line !== false) {
$url_to_delete = trim($line);
$trozos = explode(";", $url_to_delete);
$total_lines++;
if ($stmt = $mysqli->prepare("UPDATE productos SET urlRedirect = ? WHERE url = ? ")) {
$stmt->bind_param('ss', $trozos[1],$trozos[0]);
$stmt->execute(); // Execute the prepared query.
}
$stmt->close();
$line = fgets($handle);
}
fclose($handle);
}
// Output — Total Lines: 6305.
echo "Total Lines: $total_lines.\n";

I also encountered this problem before. That was around 2009 or 2010 where I need to update multiple entries fast because of the request timeout. Some solution I found was to extend the request timeout configuration of the server but another solution I found was the create a temporary table on the database server and relate the two tables but unfortunately, I cannot share with you the link because that was a long time ago.
So here what I did as long as I could recall:
Create a temporary table with similar structure to your CSV bearing the primary key to which relates to the table you like to perform the update. I know MySQL has the temporary table capability.
From your CSV, upload data by insert the record at once (by batch or multiple values on INSERT statement). This will be fast
Once you have inserted all the record, relate the temporary to your table on UPDATE statement.
Example: UPDATE orig_table ot, temp_table tt SET ot.URLRedirect=tt.URLRedirect WHERE ot.ID=tt.ID
Destroy your temporary table.
The UPDATE statement will set the value of orig_table to the new value from temp_table provided that they relate through their ID.

Related

Why mysql table id changed to descending order after running a delete query with cron?

I have a software in which I insert a 1000 phone numbers from a file(Upload a file to insert a data in mysql table). The data is inserted to the table by reading from the file. The code for this :
$handle = fopen("images/".$file_name, "r");
if ($handle) {
$i=1;
while (($line = fgets($handle)) !== false) {
$num=$line;
mysqli_query($con,"INSERT INTO sms_details (`sms`,`total_mobiles`,`user_id`,`sms_send_date`,`sms_send_time`,`status`,`file_name`,`mobiles`,`sms_count`,`reportname`) VALUES ('".$mobile_txt."','".$count_of_numbers."','".$id."','".$date."','".$date1."','DELIVRD','".$file_name."','".$num."','".$sms_count."','".$reportname."')");
}
fclose($handle);
Now I need to delete seven days old data from the database automatically so I have set a cron for this purpose. The code to delete 7 days old data is :
$date = date("Y-m-d", strtotime('-7 day'));
$qry=mysqli_query($con,"DELETE FROM sms_details WHERE `sms_send_date` < '".$date."'")
or die(mysqli_error($con));
This is working fine. But when I try to insert the new records i.e upload a new file with numbers to insert new data, the ID order (which is set to primary key and autoincrement and Order is ASC) automatically changed to Descending Order in mysqli table(phpmyadmin).In other words,the new records comes with descending id .
This is my mysqli table structure
This is a id order before run a cron to delete 7 days old records from table
This is a id order after run a cron to delete 7 days old records from table
Please suggest me why this occurs and what is the solution to this problem?

Refactor PHP script to do mysql update between 2 database servers

I'm trying to finish a script that connects to two databases, each on a different server, and preforms an update. Basically, the tables being selected from and inserted to are identical: I did a dump/import the other day. The script needs to keep my local table up to date from the remote once since there will be daily records inserted into the remote one and I need to keep it up to date locally.
The key here is that I'm determining the new rows on the remote server by looking at the Auto-incremented Primary key that the tables share, SESSIONID . I'm trying to get my loop below to say, if the id exists in remote server and not local, then insert those records in local server.
I run the below script in powershell by typing php 'filename', and I get both of my successful connection messages, but then it hangs. After about 10 minutes, it had a memory error so I added ini_set('memory_limit', '256M');. After this it would still hang for about 10 minutes, and then say that MySQL server has gone away and result header couldn't be found, both errors occurring on the line where I check to see if the $rowCount failed.
Note: Replication and large dump/import/table recreations are not an option for us in this situation. We have several similar scripts to this running and we want to keep the same process here. I'm merely looking to resolve these errors or have someone give me a more efficient way of coding this script, perhaps using a max id or something along those lines.
Here's the script:
ini_set('memory_limit', '256M');
// Create connection
$conn = new mysqli($servername, $username, $password);
$conn2 = new mysqli($servername2, $username2, $password2);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully";
// Check connection2
if ($conn2->connect_error) {
die("Connection failed: " . $conn2->connect_error);
}
echo "Connected successfully";
//Start queries
//Select All rows from the source phone database
$source_data = mysqli_query($conn, "select * from cdrdb.session");
// Loop on the results
while($source_item = $source_data->fetch_assoc()) {
// Check if row exists in destination phone database
$row_exists = $conn2->query("SELECT SESSIONID FROM ambition.session WHERE SESSIONID = '".$source_item['SESSIONID']."' ");
//if query returns false, rows don't exist with that new ID.
if (!$row_exists){
//Insert new rows into ambition.session
$conn2->query("INSERT INTO ambition.session (SESSIONID,SESSIONTYPE,CALLINGPARTYNO,FINALLYCALLEDPARTYNO,DIALPLANNAME,TERMINATIONREASONCODE,ISCLEARINGLEGORIGINATING,CREATIONTIMESTAMP,ALERTINGTIMESTAMP,CONNECTTIMESTAMP,DISCONNECTTIMESTAMP,HOLDTIMESECS,LEGTYPE1,LEGTYPE2,INTERNALPARTYTYPE1,INTERNALPARTYTYPE2,SERVICETYPEID1,SERVICETYPEID2,EXTENSIONID1,EXTENSIONID2,LOCATION1,LOCATION2,TRUNKGROUPNAME1,TRUNKGROUPNAME2,SESSIONIDTRANSFEREDFROM,SESSIONIDTRANSFEREDTO,ISTRANSFERINITIATEDBYLEG1,SERVICEEXTENSION1,SERVICEEXTENSION2,SERVICENAME1,SERVICENAME2,MISSEDUSERID2,ISEMERGENCYCALL,NOTABLECALLID,RESPONSIBLEUSEREXTENSIONID,ORIGINALLYCALLEDPARTYNO,ACCOUNTCODE,ACCOUNTCLIENT,ORIGINATINGLEGID,SYSTEMRESTARTNO,PATTERN,HOLDCOUNT,AUXSESSIONTYPE,DEVICEID1,DEVICEID2,ISLEG1ORIGINATING,ISLEG2ORIGINATING,GLOBALCALLID,CADTEMPLATEID,CADTEMPLATEID2,ts,INITIATOR,ACCOUNTNAME,APPNAME,CALLID,CHRTYPE,CALLERNAME,serviceid1,serviceid2)
VALUES ('".$source['SESSIONID']."' ,
'".$source['SESSIONTYPE']."' ,
'".$source['CALLINGPARTYNO']."' ,
'".$source['FINALLYCALLEDPARTYNO']."',
'".$source['DIALPLANNAME']."',
'".$source['TERMINATIONREASONCODE']."',
'".$source['ISCLEARINGLEGORIGINATING']."',
'".$source['CREATIONTIMESTAMP']."',
'".$source['ALERTINGTIMESTAMP']."',
'".$source['CONNECTTIMESTAMP']."',
'".$source['DISCONNECTTIMESTAMP']."',
'".$source['HOLDTIMESECS']."',
'".$source['LEGTYPE1']."',
'".$source['LEGTYPE2']."',
'".$source['INTERNALPARTYTYPE1']."',
'".$source['INTERNALPARTYTYPE2']."',
'".$source['SERVICETYPEID1']."',
'".$source['SERVICETYPEID2']."',
'".$source['EXTENSIONID1']."',
'".$source['EXTENSIONID2']."',
'".$source['LOCATION1']."',
'".$source['LOCATION2']."',
'".$source['TRUNKGROUPNAME1']."',
'".$source['TRUNKGROUPNAME2']."',
'".$source['SESSIONIDTRANSFEREDFROM']."',
'".$source['SESSIONIDTRANSFEREDTO']."',
'".$source['ISTRANSFERINITIATEDBYLEG1']."',
'".$source['SERVICEEXTENSION1']."',
'".$source['SERVICEEXTENSION2']."',
'".$source['SERVICENAME1']."',
'".$source['SERVICENAME2']."',
'".$source['MISSEDUSERID2']."',
'".$source['ISEMERGENCYCALL']."',
'".$source['NOTABLECALLID']."',
'".$source['RESPONSIBLEUSEREXTENSIONID']."',
'".$source['ORIGINALLYCALLEDPARTYNO']."',
'".$source['ACCOUNTCODE']."',
'".$source['ACCOUNTCLIENT']."',
'".$source['ORIGINATINGLEGID']."',
'".$source['SYSTEMRESTARTNO']."',
'".$source['PATTERN']."',
'".$source['HOLDCOUNT']."',
'".$source['AUXSESSIONTYPE']."',
'".$source['DEVICEID1']."',
'".$source['DEVICEID2']."',
'".$source['ISLEG1ORIGINATING']."',
'".$source['ISLEG2ORIGINATING']."',
'".$source['GLOBALCALLID']."',
'".$source['CADTEMPLATEID']."',
'".$source['CADTEMPLATEID2']."',
'".$source['ts']."',
'".$source['INITIATOR']."',
'".$source['ACCOUNTNAME']."',
'".$source['APPNAME']."',
'".$source['CALLID']."',
'".$source['CHRTYPE']."',
'".$source['CALLERNAME']."',
'".$source['serviceid1']."',
'".$source['serviceid2']."')");
}
}
// Check if row exists in destination phone database
$row_exists = $conn2->query("SELECT SESSIONID FROM ambition.session WHERE SESSIONID = '".$source_item['SESSIONID']."' ");
//if query returns false, rows don't exist with that new ID.
if (!$row_exists){
This is incorrect: if query returns false, the query failed to execute. You need to check if ($row_exists->num_rows == 0) instead. The way your code is now, it will always insert every record, again and again. Since you're not checking for errors on the INSERT query you're not noticing the failures you're getting on the duplicate entries for your SESSIONID column (I assume that's the primary key column in your local database as well).
Additionally, it would probably be a lot faster if you only SELECT the sessions you don't already have. Since you're working with an auto increment column, you can pretty much assume that anything in the remote database with a SESSIONID that came after the latest SESSIONID from your local database is new:
//Start queries
$latest_result = $conn2->query("SELECT MAX(`SESSIONID`) FROM `ambition`.`session`");
$latest_row = $latest->fetch_row();
$latest_session_id = $latest_row[0];
//Select All rows from the source phone database
$source_data = mysqli_query($conn, "SELECT * FROM `cdrdb`.`session` WHERE `SESSIONID` > $latest_session_id");
Tables in MySQL are usually sorted by the primary key column by default, but if you're concerned about the order in which you're inserting data in your local database in case your script gets interrupted for some reason, you could add an explicit ORDER BY `SESSIONID` ASC to the query.

PHP - CSV import with auto-increase ID

Sorry if this has been asked before, but I couldnt find anything that would relate to my case here on SE.
I am trying to import a CSV file into my Mysql database table with both the table the CSV having the exact same amount and order of columns, except that the table's column ID is not missing in the CSV file.
What I want to achieve is to import the CSV into the table while generating an ID number that automatically increases with each record. This does not seem possible as the CSV always seem to want to insert its data into the first colum in the table, but in my case I would need it to be the 2nd column.
How do I approach this and is there any reference code I can study? I currently am working off this PDO approach but am having the above mentioned difficulties.
PHP
<?php
$databasehost = "localhost";
$databasename = "test";
$databasetable = "sample";
$databaseusername="test";
$databasepassword = "";
$fieldseparator = ",";
$lineseparator = "\n";
$csvfile = "filename.csv";
if(!file_exists($csvfile)) {
die("File not found. Make sure you specified the correct path.");
}
try {
$pdo = new PDO("mysql:host=$databasehost;dbname=$databasename",
$databaseusername, $databasepassword,
array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)
);
} catch (PDOException $e) {
die("database connection failed: ".$e->getMessage());
}
$affectedRows = $pdo->exec("
LOAD DATA LOCAL INFILE ".$pdo->quote($csvfile)." INTO TABLE `$databasetable`
FIELDS TERMINATED BY ".$pdo->quote($fieldseparator)."
LINES TERMINATED BY ".$pdo->quote($lineseparator));
echo "Loaded a total of $affectedRows records from this csv file.\n";
?>
Thank you
You can have MySQL set values for certain columns during import. If your id field is set to auto increment, you can set it to null during import and MySQL will then assign incrementing values to it.
LOAD DATA LOCAL INFILE ".$pdo->quote($csvfile)." INTO TABLE `$databasetable`
FIELDS TERMINATED BY ".$pdo->quote($fieldseparator)."
LINES TERMINATED BY ".$pdo->quote($lineseparator))."
SET id=null;
EDIT - In case the ID column is not present in CSV
The col1, col2, col3,... are names of actual columns in the DB table (without id column)
LOAD DATA LOCAL INFILE ".$pdo->quote($csvfile)." INTO TABLE `$databasetable`
FIELDS TERMINATED BY ".$pdo->quote($fieldseparator)."
LINES TERMINATED BY ".$pdo->quote($lineseparator))."
(col1, col2, col3,...)
SET id=null;
The AUTO_INCREMENT attribute can be used to generate a unique identity for new rows. Most version of mysql and engin support this. You need not worry about the ID and can use cron job to insert the needed field and AUTO_INCREMENT will take care of the id itself.
No value was specified for the AUTO_INCREMENT column, so MySQL assigned sequence numbers automatically. You can also explicitly assign 0 to the column to generate sequence numbers, unless the NO_AUTO_VALUE_ON_ZERO SQL mode is enabled. If the column is declared NOT NULL, it is also possible to assign NULL to the column to generate sequence numbers. When you insert any other value into an AUTO_INCREMENT column, the column is set to that value and the sequence is reset so that the next automatically generated value follows sequentially from the largest column value.
You can retrieve the most recent automatically generated AUTO_INCREMENT value with the LAST_INSERT_ID() SQL function or the mysql_insert_id() C API function. These functions are connection-specific, so their return values are not affected by another connection which is also performing inserts.
See example from official link :
[https://dev.mysql.com/doc/refman/5.7/en/example-auto-increment.html]
As you want to recreate the table over and over and want to manipulate the Data from the CSV, try this:
// You have to create the TABLE if not exists
$pdo->exec("TRUNCATE TABLE sample"); // No need to drop the table if columns don't change.
$csvContent = file_get_contents($csvfile); // Raw Data from file
$lines = explode("
", $csvContent); // The standard line separator is an ENTER
// Now you have each line separated
for($i = 0; $i < coount($lines); $i++) {
$col = explode(";", $lines[$i]); // Would be a comma
// Now you have each column separated
$pdo->exec("INSERT INTO sample (id, col1, col2, col3 ... coln) VALUES (NULL, '".$col[0]."', '".$col[1]."', '".$col[2]."' ... '".$col[n]."')");
}
This way you can dig into your Data and, besides setting an AUTO_INCREMENT ID, you can validate what is coming from the CSV and can correct/prevent importation errors.

How to delete particular columns data in database using php mysql [duplicate]

This question already has answers here:
mysql_fetch_array()/mysql_fetch_assoc()/mysql_fetch_row()/mysql_num_rows etc... expects parameter 1 to be resource
(31 answers)
Closed 7 years ago.
Hi iam trying to delete certain columns data from database.Here is my code for delete query.
//getting column id by comparing the id need to delete the data from that row.
$id=$_GET['id'];
$res = "DELETE rental_annual_rent,
rental_block,
rental_street,
rental_area,
rental_town,
rental_state,
rental_pincode
FROM house_details
WHERE house_details_id='$id'";
$result=mysql_query($res);
if(mysql_affected_rows()){
echo "successfully deleted";
session_start();
header("Location:property.php");
}else{
echo "Failure";
}
First iam inserting house_details data into database but i need to delete only particular data from that columns
What you want is an UPDATE, not a DELETE since you want to keep the row, but just clear/blank/unset certain columns within the row.
$res = "UPDATE house_details SET
rental_annual_rent = NULL,
rental_block = NULL,
rental_street = NULL,
rental_area = NULL,
rental_town = NULL,
rental_state = NULL,
rental_pincode = NULL
WHERE house_details_id='$id'";
Note that you should really be sanitizing your id input before using it in the query, you should parameterize it, and you should also migrate from the mysql library to mysqli or PDO

How to insert multiple values in a specific field in a table using mysqli? [duplicate]

This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
Closed 7 years ago.
I am working on a project and I I have a scenario like this:
I have many field in my table :
table_name : transaction_tbl
-id
-name
-description
-ref_number : text(datatype)
In my inserting here is my code:
$sql = "INSERT INTO transaction_tbl (`name`,`description`,`ref_number`) VALUES ('$name','$desccription',$ref_number)";
if ($conn->query($sql) === false){
trigger_error('Wrong SQL: ' . $sql . 'Error: ' . $conn->error , E_USER_ERROR);
}else {
echo "Successful ! Data is inserted in database ^__^" ;
}
As the name itself ref_number or reference number, so there will be a time that I will have a lot of reference number,how can I let it insert if it will have multiple values?
Thanks :)
UPDATE :
I want something like this :
name description ref_number
bag to be use 10359435846
05438547656
035848576
Its not a good practice to have multiple values in one cell (and you should never unless there is a serious reason). It violates basic db rules. Just split this to two tables and assign foreign keys to link them up.
Learn db normalization. There are lot of examples. In here you need to take your un-normalized (0NF) table to at least to 1st normalized level (1NF). But its advised to make it normalized at least up to 3rd level
google for db normalization tutorials. As you request below image will give you an idea(field names are not same as in your question).
First insert the values to table1(Member table) and get the insert id in php use $iid = mysqli_insert_id()
Next add the multiple values as seperate rows into the second table(database table) along with the primary key obtained in first step.
Keep in mind this is not a tutorial site. find more info on net.
for what purpose ? why don't you just insert a new row with the same name and description with different ref_number ?
but if you would like that , you can concatenate your new ref_number with the existing ..
first check if it already exist
get its value then concatenate the new ref number ..
or if it doesn't exist , insert a new row ..
$sql = "SELECT `ref_number` FROM `transaction_tbl`
WHERE `name`='$name' AND `description`='$description'";
$query = mysql_query($sql);
if(mysql_num_rows($query) > 0)
{
$row = mysql_fetch_array($query);
$new_ref = $row['ref_number'] . '|' . $ref_number;
$upd = "UPDATE `transaction_tbl` SET `ref_number`='$new_ref'
WHERE `name`='$name' AND `description`='$description'";
}
else
{
$ins = "INSERT INTO transaction_tbl (`name`,`description`,`ref_number`)
VALUES ('$name','$desccription',$ref_number)";
mysql_query($ins);
}

Categories