У меня есть хорошая письменная функция; Я думаю, но когда я использую эту функцию на клиенте, у которого много транзакций, это занимает около 20 секунд, увеличиваясь каждый раз, когда я добавляю новую транзакцию. Эта функция начинает пересчитывать все долги клиентов с самого начала. Я использую :
Я пробовал некоторые изменения в php.ini
php.ini
post_max_size = 256M
upload_max_filesize = 128M
memory_limit = 1G
max_input_vars = 10000
и
мой.ini
key_buffer_size = 256M
max_allowed_packet = 128M
sort_buffer_size = 128M
net_buffer_length = 8K
read_buffer_size = 128M
read_rnd_buffer_size = 128M
myisam_sort_buffer_size = 512M
innodb_buffer_pool_size = 256M
innodb_log_file_size = 256M
innodb_log_buffer_size = 512M
[mysqldump]
quick
max_allowed_packet = 512M
[isamchk]
key_buffer_size = 512M
sort_buffer_size = 128M
read_buffer_size = 256M
write_buffer_size = 256M
[myisamchk]
key_buffer_size = 512M
sort_buffer_size_size = 512M
read_buffer_size = 256M
write_buffer_size = 256M
а вот функция
function reCalculateAll($conn, $clid, $cltp){
$stmt = $conn->prepare("SELECT * FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt->bind_param('is', $clid, $cltp);
$stmt->execute();
$results = $stmt->get_result();
$stmt->fetch();
$numberofrows = $stmt->num_rows;
while ($row = $results->fetch_assoc()) {
$r = getAllTransactionsClient($conn, $clid, $cltp);
$result = array();
foreach($r as $i => $p){
$result[$p['client_type'].$p['client_id']][] = $p;
foreach ($result as $rr){
foreach ($rr as $c => $k){
reset($rr);
$trid = $k['id'];
$trcn = $k['client_id'];
$trtp = $k['client_type'];
$trdt = $k['transaction_date'];
if ($c === key($rr)){
// FIX TRANSACTION
$addm = 0;
$stmtf = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? + added_amount where id = ?");
$stmtf->bind_param('ssi', $addm, $addm, $trid);
$stmtf->execute();
$stmtf->close();
$addm = $k['client_newfunds'];
} else {
$stmtn = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? + added_amount where id = ?");
$stmtn->bind_param('ssi', $addm, $addm, $trid);
$stmtn->execute();
$stmtn->close();
$addm = $k['client_newfunds'];
}
$cnf = getLastDebtFromTransaction($conn, $trtp, $trcn);
setDebts($conn, $trtp, $cnf, $trcn);
}
}
}
}
$results->free();
$stmt->execute();
$stmt->store_result();
$numberofrows = $stmt->num_rows;
if ($numberofrows == 0){
setDebts($conn, $cltp, '0', $clid);
}
$stmt->close();
}
Функция getAllTransactionsClient
function getAllTransactionsClient($conn, $clid, $cltp){
$stmt = $conn->prepare("SELECT * FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt->bind_param('is', $clid, $cltp);
$stmt->execute();
$result = $stmt->get_result();
$products = array();
while ($row = $result->fetch_assoc()) {
$products[] = $row;
}
return $products;
$stmt->close();
}
@MagnusEriksson, какие показатели? вы имеете в виду данные?
отредактируйте вопрос, чтобы включить вывод SHOW CREATE transactions
. Насколько большой стол. Выполнение обновлений в цикле не является чем-то удобным для базы данных. Серверы SQL хорошо выполняют циклы, поэтому вам это не нужно. reCalculateAll должен быть одним оператором SQL. Подготовка заявления должна выходить за рамки цикла. Добро пожаловать в СО
Под показателями я подразумеваю цифры. Если ваш запрос на выборку возвращает 2 транзакции для повторения, то 20 секунд — это много. Если ваш запрос на выборку возвращает 1 000 000 транзакций, то 20 секунд — это довольно быстро (поскольку вы обновляете их в цикле).
@danblack спасибо, что нашли время прочитать мой вопрос и ответить на него, я постараюсь найти способ заменить эти несколько циклов, но я создал этот код под давлением и в кратчайшие сроки, просто чтобы решить проблему с моим программным обеспечением, все еще ищу для лучших идей
@MagnusEriksson около 40 транзакций, но их количество увеличивается
Что делает getAllTransactionsClient
? Вы вызываете процедуру в цикле, каждый раз передавая одни и те же параметры. Вы также передаете $conn
, пока у вас все еще есть строки из первого запроса в буфере.
@slaakso, проверь мой вопрос еще раз, я добавил эту функцию в конец
Итак, вы повторяете один и тот же запрос в цикле, с которого он начался? Это не имеет смысла. Затем у вас есть вызовы getLastDebtFromTransaction
и setDebts
в цикле, которые, вероятно, делают похожие вещи, и снова вы передаете один и тот же $conn
, пока основной запрос все еще выполняется. Может быть, просто перепишите всю функцию как один запрос или вызов хранимой процедуры.
Можете ли вы объяснить, что ваш код должен делать?
Пре-курсор
Я собираюсь пропустить "ответ на ваш вопрос" - я думаю, что многие проблемы освещены в комментариях выше - и перейду прямо к решению того, что, как я думаю, вы намереваетесь сделать в своем коде...
Однако вашему коду нелегко следовать, я считаю, что суть проблемы заключается в следующем:
Ваша база данных каким-то образом повреждена, и поля client_oldfunds
и client_newfunds
больше не содержат правильных данных.
Вы уверены, что поле added_amount
правильное, и хотите вернуться и пересчитать поля выше для каждой транзакции, чтобы все совпало?
Структура таблицы
CREATE TABLE transactions (
id bigint AUTO_INCREMENT PRIMARY KEY,
client_id bigint,
client_type varchar(20),
client_oldfunds decimal(10,2),
client_newfunds decimal(10,2),
added_amount decimal(10,2),
transaction_date varchar(20)
);
Пример текущих данных
Предположим, что транзакции здесь упорядочены по дате.
id | client_id | client_type | client_oldfunds | client_newfunds | added_amount
--- | ----------- | ------------- | ----------------- | ----------------- | --------------
1 | 1 | type_a | 12.10 | 1.36 | 3.12
2 | 1 | type_a | 6.00 | 432.42 | 4.50
3 | 1 | type_a | 30.12 | 1.33 | 100.22
4 | 1 | type_a | 23.1 | 1.22 | 10.2
5 | 1 | type_a | 123.4 | 55.54 | 12.6
Пример правильных данных
Предположим, что транзакции здесь упорядочены по дате.
id | client_id | client_type | client_oldfunds | client_newfunds | added_amount
--- | ----------- | ------------- | ----------------- | ----------------- | --------------
1 | 1 | type_a | 0 | 3.12 | 3.12
2 | 1 | type_a | 3.12 | 7.62 | 4.50
3 | 1 | type_a | 7.62 | 107.84 | 100.22
4 | 1 | type_a | 107.84 | 118.04 | 10.2
5 | 1 | type_a | 118.04 | 130.64 | 12.6
Что мы хотим, чтобы он делал
reCalculateAll{
0 > Initialise a balance of 0
1 > SELECT id and amount_added for all related transactions, in order
2 > UPDATE the client_oldfunds to the balance and client_newfunds to the balance + the added_amount
3 > UPDATE the balance to the new value (balance + added_amount)
}
Фактический код
function reCalculateAll($mysqli, $client_id, $client_type){
$select_sql = "
SELECT id, added_amount
FROM transactions
WHERE client_id = ?
AND client_type = ?
ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC
";
$select_query = $mysqli->prepare($select_sql);
$select_query->bind_param("is", $client_id, $client_type);
$select_query->execute();
$select_query->store_result();
$select_query->bind_result($transaction_id, $added_amount);
$old_balance = 0;
while($select_query->fetch()){
$new_balance = $old_balance + $added_amount;
$update_sql = "
UPDATE transactions
SET client_oldfunds = ?,
client_newfunds = ?
WHERE id = ?
";
$update_query = $mysqli->prepare($update_sql);
$update_query->bind_param("ssi", $old_balance, $new_balance, $transaction_id);
$update_query->execute();
$old_balance = $new_balance;
}
}
Н.Б.
Вы действительно должны хранить свои даты в формате MySQL «Y-m-d H: i: s». Это упрощает сортировку; форматирование должно происходить при выводе даты в браузер.
Ваш код нуждается в улучшении, я вижу, что в одном есть несколько циклов, Вот ваша первая функция, вы можете избавиться от последней, потому что она бесполезна.
Фактическая функция должна быть такой:
function reCalculateAll($conn, $client_id, $client_type){
// THE FOLLOWING QUERY WILL REPLACE this function for you getAllTransactionsClient();
$stmt = $conn->prepare("SELECT id, added_amount FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt -> bind_param("is", $client_id, $client_type);
$stmt -> execute();
$stmt -> store_result();
$stmt -> bind_result($transaction_id, $added_amount);
// THIS $oldfunds stands for your old $addm
$oldfunds = 0;
while($stmt->fetch()){
$newfunds = $oldfunds + $added_amount;
$stmtd = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? WHERE id = ?");
$stmtd->bind_param("ssi", $oldfunds, $newfunds, $transaction_id);
$stmtd->execute();
$oldfunds = $newfunds;
}
$stmt->close();
// this should send 0 if there is no transactions
setDebts($conn, $client_type, $oldfunds, $client_id);
}
Не могли бы вы сообщить нам некоторые показатели? О каком количестве транзакций идет речь? Сколько запросов на обновление выполняется?