tags:

views:

763

answers:

6

Is it possible to do a simple count(*) query in a php script while another php script is doing insert...select... query?

The situation is that I need to create a table with ~1M or more rows from other table, and while inserting, I do not want the user feel the page is freezing, so I am trying to keep update the counting, but by using a select count(*) from table when background in inserting, I got only 0 until the insert is completed.

So is there any way to ask MySQL returns partial result first? Or is there a fast way to do series of insert with data fetched from a previous select query while having about the same performance as insert...select... query?

The environment is php4.3 and MySQL4.1.

A: 

The other users can't see the insertion until it's committed. That's normally a good thing, since it makes sure they can't see half-done data. However, if you want them to see intermediate data, you could throw in an occassional call to "commit" while you're inserting.

By the way - don't let anybody tell you to turn autocommit on. That a HUGE time waster. I have a "delete and re-insert" job on my database that takes 1/3rd as long when I turn off autocommit.

Paul Tomblin
+3  A: 

Without reducing performance? Not likely. With a little performance loss, maybe...

But why are you regularily creating tables and inserting millions of row? If you do this only very seldom, can't you just warn the admin (presumably the only one allowed to do such a thing) that this takes a long time. If you're doing this all the time, are you really sure you're not doing it wrong?

Stein G. Strindhaug
A: 

Just to be clear, MySQL 4 isn't configured by default to use transactions. It uses the MyISAM table type which locks the entire table for each insert, if I remember correctly.

Your best bet would be to use one of the MySQL bulk insertion functions, such as LOAD DATA INFILE, as these are dramatically faster at inserting large amounts of data. As for the counting, well, you could break the inserts into N groups of 1000 (or Y) then divide your progress meter into N sections and just update it on each group's request.

Edit: Another thing to consider is, if this is static data for a template, then you could use a "select into" to create a new table with the same data. Not sure what your application is, or the intended functionality, but that could work as well.

Abyss Knight
LOAD DATA INFILE takes data from a file, not a SELECT from another table, as the OP is doing. One would have to copy the results of that SELECT out to a temporary file, before one can load it. This may not be any improvement over the current solution.
Bill Karwin
True, very true. I think we need more information from the OP regarding the use case. Using a select x into tablename may be of some use, however. It all depends on what the end goal is.
Abyss Knight
A: 

If you're doing a single INSERT...SELECT, then no, you won't be able to get intermediate results. In fact this would be a Bad Thing, as users should never see a database in an intermediate state showing only a partial result of a statement or transaction. For more information, read up on ACID compliance.

That said, the MyISAM engine may play fast and loose with this. I'm pretty sure I've seen MyISAM commit some but not all of the rows from an INSERT...SELECT when I've aborted it part of the way through. You haven't said which engine your table is using, though.

bradheintz
+2  A: 

I agree with Stein's comment that this is a red flag if you're copying 1 million rows at a time during a PHP request.

I believe that in a majority of cases where people are trying to micro-optimize SQL, they could get much greater performance and throughput by approaching the problem in a different way. SQL shouldn't be your bottleneck.

Bill Karwin
A: 

If you can get to the console, you can ask various status questions that will give you the information you are looking for. There's a command that goes something like "SHOW processlist".

le dorfier