it-swarm.dev

Bagaimana cara menetapkan waktu eksekusi maksimum untuk permintaan mysql?

Saya ingin menetapkan waktu eksekusi maksimum untuk kueri sql seperti set_time_limit () di php. Bagaimana saya bisa melakukannya?

20
microry

Saya pikir sudah ada sedikit lebih lama, tetapi menurut ini

MySQL 5.7.4 memperkenalkan kemampuan untuk menetapkan batas waktu eksekusi sisi server, ditentukan dalam milidetik, untuk pernyataan SELECT hanya-baca tingkat atas.

SELECT 
MAX_EXECUTION_TIME = 1000 --in milliseconds
* 
FROM table;

Perhatikan bahwa ini hanya berfungsi untuk pernyataan SELECT baca-saja.

Pembaruan: Variabel ini ditambahkan di MySQL 5.7.4 dan diubah namanya menjadi max_execution_time di MySQL 5.7.8. ( sumber )

20
Westy92

Jika Anda menggunakan mysql native driver (umum sejak php 5.3), dan mysqli extension, Anda dapat melakukannya dengan permintaan asinkron:

<?php

// Here's an example query that will take a long time to execute.
$sql = "
    select *
    from information_schema.tables t1
    join information_schema.tables t2
    join information_schema.tables t3
    join information_schema.tables t4
    join information_schema.tables t5
    join information_schema.tables t6
    join information_schema.tables t7
    join information_schema.tables t8
";

$mysqli = mysqli_connect('localhost', 'root', '');
$mysqli->query($sql, MYSQLI_ASYNC | MYSQLI_USE_RESULT);
$links = $errors = $reject = [];
$links[] = $mysqli;

// wait up to 1.5 seconds
$seconds = 1;
$microseconds = 500000;

$timeStart = microtime(true);

if (mysqli_poll($links, $errors, $reject, $seconds, $microseconds) > 0) {
    echo "query finished executing. now we start fetching the data rows over the network...\n";
    $result = $mysqli->reap_async_query();
    if ($result) {
        while ($row = $result->fetch_row()) {
            // print_r($row);
            if (microtime(true) - $timeStart > 1.5) {
                // we exceeded our time limit in the middle of fetching our result set.
                echo "timed out while fetching results\n";
                var_dump($mysqli->close());
                break;
            }
        }
    }
} else {
    echo "timed out while waiting for query to execute\n";
    var_dump($mysqli->close());
}

Bendera yang saya berikan ke mysqli_query selesaikan hal-hal penting. Ia memberi tahu driver klien untuk mengaktifkan mode asinkron, sementara memaksa kami untuk menggunakan lebih banyak kode verbose, tetapi memungkinkan kami menggunakan batas waktu (dan juga mengeluarkan kueri bersamaan jika Anda mau!). Bendera lainnya memberi tahu klien untuk tidak buffer seluruh hasil yang ditetapkan ke dalam memori. 

Secara default, php mengonfigurasi pustaka klien mysql untuk mengambil seluruh rangkaian hasil kueri Anda ke dalam memori sebelum memungkinkan kode php Anda mulai mengakses baris dalam hasilnya. Ini bisa memakan waktu lama untuk mentransfer hasil yang besar. Kami menonaktifkannya, jika tidak, kami berisiko kami akan kehabisan waktu sambil menunggu penyanggaan selesai.

Perhatikan bahwa ada dua tempat di mana kita perlu memeriksa melebihi batas waktu: 

  • Eksekusi query yang sebenarnya
  • saat mengambil hasil (data)

Anda dapat melakukan hal serupa di PDO dan ekstensi mysql reguler. Mereka tidak mendukung permintaan yang tidak sinkron, sehingga Anda tidak dapat menetapkan batas waktu pada waktu eksekusi permintaan. Namun, mereka mendukung set hasil yang tidak dikonstruksikan, dan karenanya Anda setidaknya dapat menerapkan batas waktu pada pengambilan data.

Untuk banyak kueri, mysql dapat mulai mengalirkan hasilnya kepada Anda hampir dengan segera, dan dengan demikian permintaan yang tidak terbaca sendiri akan memungkinkan Anda untuk menerapkan timeout agak efektif pada kueri tertentu. Misalnya, a 

select * from tbl_with_1billion_rows

dapat mulai streaming baris segera, tetapi, 

select sum(foo) from tbl_with_1billion_rows

perlu memproses seluruh tabel sebelum dapat mulai mengembalikan baris pertama kepada Anda. Kasus terakhir ini adalah di mana batas waktu pada kueri asinkron akan menyelamatkan Anda. Ini juga akan menyelamatkan Anda dari kebuntuan tua dan hal-hal lainnya.

ps - Saya tidak memasukkan logika batas waktu pada koneksi itu sendiri.

8
goat

Anda dapat menemukan jawabannya di S.O. lainnya ini pertanyaan:

MySQL - dapatkah saya membatasi waktu maksimum yang diizinkan untuk menjalankan kueri?

pekerjaan cron yang berjalan setiap detik di server database Anda, menghubungkan dan melakukan sesuatu seperti ini:

  • TAMPILKAN PROSESLIST
  • Temukan semua koneksi dengan waktu kueri yang lebih besar dari waktu maksimum yang Anda inginkan
  • Jalankan KILL [id proses] untuk masing-masing proses tersebut
4
Rafa

Silakan tulis ulang kueri Anda seperti

select /*+ MAX_EXECUTION_TIME(1000) */ * from table

3
Manu Mohan T

pt_kill memiliki opsi untuk itu. Tapi itu sesuai permintaan, tidak terus-menerus memantau. Itu melakukan apa yang disarankan @Rafa. Namun lihat --sentinel untuk petunjuk bagaimana mendekati cron.

0
Rick James