PHP bir seferde SQL sorgusu bir kısmını çalıştırmak için nasıl?

8 Cevap php

Ben kabaca 1 milyon satır ile bir tablo var. Ben her satırdan bir alan yazdıran basit bir program yapıyorum. Ben sorgu uzun zaman alacağını mysql_pconnect ve mysql_query kullanmaya başladı Ancak, ben sorgu ben bile ilk satırını yazdırabilirsiniz önce bitirmek gerekiyor varsayarak yaşıyorum. Bir defada bir veri biraz işlemek için bir yolu var mı?

--Edited-- I am not looking to retrieve a small set of the data, I'm looking for a way to process the data a chunk at a time (say fetch 10 rows, print 10 rows, fetch 10 rows, print 10 rows etc etc) rather than wait for the query to retrieve 1 million rows (who knows how long) and then start the printing.

8 Cevap

Bir milyon alanları yazdırma biraz zaman alacaktır. Bir milyon kayıtları alınırken biraz zaman alacaktır. Zaman kadar ekler.

Kodunuzu profilli var? Ben limitini kullanarak bu durumda böyle bir köklü fark yapar emin değilim.

Böyle bir şey yaptığını

while ($row = mysql_fetch_object($res)) {
   echo $row->field."\n";
}

Bir anda çıktılar bir kayıt. Bütün resultset iade edilmesi için beklemez.

Eğer bir tarayıcı ile ilgili iseniz size daha fazla bir şey gerekir.

Bu gibi, bu gibi

ob_start();
$i = 0;
while ($row = mysql_fetch_object($res)) {
   echo $row->field."\n";
   if (($i++ % 1000) == 0) {
       ob_flush();
   }
}
ob_end_flush();

Eğer gerçekten bir milyon alanları yazdırmak istiyor musunuz?

Alışılmış çözüm sonucunda sadece bir kısmını gösteren, web uygulaması çıktı pagination çeşit kullanmaktır. On SELECT Eğer verilerin sadece bir kısmını geri dönmek için LIMIT anahtar kelime kullanabilirsiniz sorgular. Bu gerçekten, temel SQL şeyler. Örnek:

SELECT * FROM table WHERE (some conditions) LIMIT 40,20

(mümkün olabilir benim parçası üzerinde bir hata kapalı) 40. başlayarak, 20 girişleri gösterir.

Bu rastgele istekleri arasında ayaklarınızın altında değiştirmesini sipariş engellemek için ORDER BY LIMIT ile birlikte kullanmak için gerekli olabilir.

Bu genellikle numaralandırılmasını gereklidir. Eğer select sorgusunda sınır kelime kullanabilirsiniz. Sınırı için ara here:

LIMIT deyimi SELECT ifadesinin döndürdüğü satır sayısını sınırlamak için kullanılır. SINIR ikisi (hazırlanmış deyimleri kullanırken hariç) negatif olmayan bir tamsayı sabitleri olması gerekir, bir veya iki sayısal argüman alır.

Iki argüman ile, ilk argüman dönmek için ilk satırın offset belirtir ve ikinci dönmek için satır sayısını belirtir. 0 (değil 1) ilk satırın ofset:

SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

Sonuç kümesinin sonuna kadar ofset belirli bir tüm satırları almak için, ikinci parametre için bazı büyük numarasını kullanabilirsiniz. Bu ifade 96 satırdan son tüm satırları alır:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

Bir argüman ile, değer sonuç kümesinin başından geri dönmek için satır sayısını belirtir:

SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows

Diğer bir deyişle, LİMİT row_count 0, ROW_COUNT SINIR eşdeğerdir.

You might be able to use Mysqli::use_result

Tarayıcıda ayarlanmış bir flush çıkışına verilerle birleştirilerek. Ben mysqli :: use_result eksik sonuç kümelerini almak için doğru fonksiyon olup olmadığını ancak ben emin değilim, ben sadece bunu yapmak için önce kullanmış gibi gömme bir artan devlet tarayıcıya çıkış veri kullanılabilir biliyorum.

Bu benim Oracle böyle bir şey yapmak nasıl. Ben aşıp nasıl emin değilim:

declare
my_counter integer := 0;
begin
for cur in (
select id from table
) loop
  begin
    -- do whatever your trying to do
    update table set name = 'steve' where id = cur.id;
    my_counter := my_counter + 1;
    if my_counter > 500 then
      my_counter := 0;
      commit;
    end if;
    end;
  end loop;
  commit;
end;

Temel MySQL sürücüsü kullanılarak bir örnek.

define( 'CHUNK_SIZE', 500 );

$result = mysql_query( 'select count(*) as num from `table`' );
$row = mysql_fetch_assoc( $result );

$totalRecords = (int)$row['num'];

$offsets = ceil( $totalRecords / CHUNK_SIZE );

for ( $i = 0; $i < $offsets; $i++ )
{
  $result = mysql_query( "select * from `table` limit " . CHUNK_SIZE . " offset " . ( $i * CHUNK_SIZE ) );
  while ( $row = mysql_fetch_assoc( $result ) )
  {
    // your per-row operations here
  }
  unset( $result, $row );
}

Bu, tüm satır hacmi üzerinde yineleme, ama aşağı bellek kullanımını korumak için bir seferde bu yüzden sadece 500 satır yapacağız.

Eğer mysql sunucu içinde değişik tampon boyutlarda sınırlarını vuruyorlar gibi geliyor ... yapabileceği bazı yöntemler bu tampon boyutunu azaltmak için SQL deyiminde istediğiniz alanı belirtmek için olabilir, ya da çeşitli admin ile oynamak istiyorum ayarlar.

OR, bir sayfalama like yöntemi kullanabilirsiniz ama tek sayfada tüm çıkış var ...

(Pseudocode)

 function q($part) {
      $off = $part*SIZE_OF_PARTITIONS;
      $size = SIZE_OF_PARTITIONS;

      return( execute_and_return_sql('SELECT `field` FROM `table` LIMIT $off, $size'));
    }

    $ii = 0;

    while ($elements = q($ii)) {
      print_fields($elements);
      $ii++;
    }

mysql_unbuffered_query() or if using PDO make sure PDO::MYSQL_ATTR_USE_BUFFERED_QUERY olduğu kullanarak false.

Ayrıca bkz: this similar question.

Edit: ve diğerleri söylediler, içinde bulunduğunuz koşullara bağlı olarak, işleme her parti sonra çıkış tampon yıkama ile birleştirmek isteyebilirsiniz.