QT wrote:
> I have a database with thousands records. And every minutes I am selecting
> 50 rows from that database and send some data to another web url according
> sellected 50 rows.
>
> Whenever, my script finish job in one minute, I have no problem. Because
> after each transaction, I am uptading one of the rows field as a "uesd".

If you actually have MySQL transactions, you should be able to wrap the
entire process in a single transaction, and it should work -- assuming
MySQL transactions pass the whole ACID test...  You'll have to read the
MySQL manual and understand ACID, which I only grok as I read it, not at
all times, or I'd just tell you what you need to know.  Sorry.

> BUT! if my script can not finish sending data to another url due to low
> speed connection or such a problem. On the next minute, same script runs
> automaticlay and sellecting another 50 rows which are not marked by
> "used".
>
> In this case, some times these two running acripts are sellecting same
> rows
> due to, old one haven't marked as a "used" for sellected rows.
>
> Is there any way, to put flag or something like that, when sellecting rows
> with php and mysql?

Ah.

Given the problem you are facing, of a slow connection, you probably don't
want to tie up the whole table while running your script with a
transaction in the first place -- MySQL still does a table-level lock,
right?...  Maybe not.  Again, you'd have to read the MySQL docs carefully,
and be sure your version of MySQL matches, to see if they do row-level
locking.

Without row-level locking, your other scripts will wait for the slow
connection to release the whole table from its locked state.

That would probably be "bad" for most applications.

Here is what I would try if I were you:

//Possibly START a MySQL transaction HERE:
$query = "select table_id from your_table where not status = 'used' limit
50";
$selected = @mysql_query($query, $connection) or
trigger_error(@mysql_error($connection) . " $query", E_USER_ERROR);
$selected_ids = array();
while (list($id) = @mysql_fetch_row($selected)){
  $selected_ids[] = $id;
}
$selected_ids_sql = implode(', ', $selected_ids);
$query = "update your_table set status = 'used' where table_id in
($selected_ids_sql)";
$used = @mysql_query($query, $connection) or
trigger_error(@mysql_error($connection) . " $query", E_USER_ERROR);
//END the transaction started above here.

//*NOW* go ahead and get the stuff you want from your selected records
//and send them off to that slow connection:
$query = "select fields, you, really, want from your_table where table_id
in ($selected_ids_sql) ";
$data = @mysql_query($query, $connection) or
trigger_error(@mysql_error($connection) . " $query", E_USER_ERROR);
while (list($fields, $you, $really, $want) = @mysql_fetch_row($data)){
  //Send this row to the slow connection
}

By dealing with *ALL* the rows at once when you first SELECT them, and
then doing an UPDATE on *ALL* the rows at once right away, you can keep
the other scripts from getting confused about which records are 'used'.

If you wrap just that part of the code in a MySQL transaction, you make it
virtually 100% "safe" [*] for the other scripts.

Most importantly, by pulling the SELECT and UPDATE out, you can handle the
'used' attribute in a transaction *quickly* without bogging down your
application waiting for that slow connection or even just getting all the
data from MySQL to PHP.  You really only care about the ID field (assuming
you have one) and the 'used' status in terms of speed and in terms of
tracking which records were 'sent' probably.

This all assumes that you don't care if the slow connection gets its
records *AFTER some other fast connection gets the next 50 records...  If
that's not what your application needs, DON'T DO THIS. :-)

[*] NOTE:
The transaction is 100% safe, but if your slow connection dies, you've got
a bunch of records marked 'used' that were *NOT* really 'used' because the
script died after you marked them 'used'

Hopefully, that's a fairly rare occurence, right?

Since it is rare, if you can write your code to DETECT that the slow
connection died, and the records you tried to send didn't really get sent,
in that last loop, you can update a single record's 'used' setting to put
it back to 'unused' (or whatever you call it) if it fails to be sent.

So the basic algorithm is:

BEGIN TRANSACTION
  SELECT 50 ids
  UPDATE those 50 ids as 'used' in ONE query
END TRANSACTION
[the above should happen about as fast as PHP/MySQL can go]
SELECT actual data for selected 50 ids
send data to client
if a record fails to send, re-set status to not be 'used' so it can get
sent in a later batch.

The down-side is that faster connections will get records "out of
sequence" while the slower connection is still chugging away trying to
process the records that are "earlier" in your sequence.  In most
applications of this nature, that's okay.

If that's not okay, this is entirely the wrong algorithm to use, and you
need to wrap the whole thing in a TRANSACTION and accept the fact that
your slow connection is going to lock up your entire database until it
finishes all 50 records...  At which point you can try some combination of
things like:
  Send less than 50 records, at least to connections that have been proven
to be "slow" in the past.
  Buy more hardware or acceleration software to make up for the slowness
of some connections by making all the rest go faster, and hope it
averages out.
  Build in a system of detecting slow connections and roll back your
transactions when something is too slow, and hope the next time it's
faster.

What you do among all these choices depends more on your application's
needs than on what's "fastest" or "best" really.

-- 
Like Music?
http://l-i-e.com/artists.htm

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to