Как решить проблему блокировки обновления в MySQL - PullRequest
0 голосов
/ 18 февраля 2020

У меня 2 MySQL Проблема ОБНОВЛЕНИЯ запроса на моем веб-сайте.

Проблема 1

Я запускаю контентный сайт, который обновляет просмотры страниц для сообщений, когда пользователи читают .

Каждый раз, когда я отправляю уведомления pu sh, мой сервер отключается; когда я комментирую запрос на обновление, который увеличивает количество просмотров страниц, все возвращается на круги своя.

Я думаю, что это может быть результатом сотен запросов UPDATE, пытающихся обновить представления в одной строке.

**The query that updated the tablename**    

update table set views='$newview' where id=1


Query Explain

id: 1
select_type: SIMPLE
table: new_jobs
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: NULL
rows: 1
Extra: Using where


**tablename create table**

CREATE TABLE `tablename` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `company_id` int(11) DEFAULT NULL,
 `job_title` varchar(255) DEFAULT NULL,
 `slug` varchar(255) DEFAULT NULL,
 `advert_date` date DEFAULT NULL,
 `expiry_date` date DEFAULT NULL,
 `no_deadline` int(1) DEFAULT 0,
 `source` varchar(20) DEFAULT NULL,
 `featured` int(1) DEFAULT 0,
 `views` int(11) DEFAULT 1,
 `email_status` int(1) DEFAULT 0,
 `draft` int(1) DEFAULT 0,
 `created_by` int(11) DEFAULT NULL,
 `show_company_name` int(1) DEFAULT 1,
 `display_application_method` int(1) DEFAULT 0,
 `status` int(1) DEFAULT 1,
 `upload_date` datetime DEFAULT NULL,
 `country` int(1) DEFAULT 1,
 `followers_email_status` int(1) DEFAULT 0,
 `og_img` varchar(255) DEFAULT NULL,
 `old_id` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `new_jobs_company_id_index` (`company_id`),
 KEY `new_jobs_views_index` (`views`),
 KEY `new_jobs_draft_index` (`draft`),
 KEY `new_jobs_country_index` (`country`)
) ENGINE=InnoDB AUTO_INCREMENT=151359 DEFAULT CHARSET=utf8

Как лучше всего с этим справиться?

[Сценарий 2 удален по запросу]

1 Ответ

1 голос
/ 18 февраля 2020

Сценарий 1. Я ожидаю, что обновление счетчика 'view' (или 'click' или 'like' или что-то еще) будет больше похоже на

UPDATE t SET views = views + 1 WHERE id = 123;

Я предполагаю, что у вас есть индекс (возможно, PRIMARY KEY) на id?

Поскольку с этой таблицей происходят другие вещи, может быть целесообразно разделить быстро увеличивающийся счетчик на отдельную таблицу. Это позволит избежать вмешательства в другие запросы. Вы можете получить другие данные, плюс счетчик, используя JOIN .. USING(id).

Сценарий 2 не имеет смысла. Кажется, для каждого письма сохраняется самая последняя дата, но что означает country? Поскольку это кажется больше, чем просто счетчик, вы можете захотеть, чтобы отдельная таблица регистрировала эти 3 столбца.

Пожалуйста, укажите SHOW CREATE TABLE.

Есть много вещей, которые новички воспринимают как " CRA sh». Пожалуйста, опишите подробнее - нет подключений, недостаточно места на диске, медлительность, клиент выдал сообщение об ошибке, другие операции заняли слишком много времени и т. Д. c. У каждого есть свое лекарство.

Запрос

Вы в настоящий момент логически делаете

BEGIN;
$ct = SELECT views ... FOR UPDATE;
...
UPDATE ... SET views = $ct+1 WHERE ...;
COMMIT;

Если это так, это гораздо менее эффективно, чем

(with autocommit = ON)
UPDATE ... SET views = views+1 ...;

Обратите внимание, что первая версия дольше висит на строке. Если вам не удастся использовать FOR UPDATE, вы потеряете некоторые значения.

Разделение на отдельную таблицу заставляет вас запускать UPDATE как свою собственную транзакцию.

Другое

innodb_flush_log_at_trx_commit:

  • По умолчанию установлено значение 1, которое является безопасным, но приводит к как минимум одному IOP для каждой транзакции.
  • 2 отведения гриппу sh раз в секунду. В напряженные времена это гораздо эффективнее. Но Cra sh может потерять до одной секунды обновлений. неточность «количества просмотров» из-за редкого cra sh, на мой взгляд, приемлема.

KEY(views) необходимо обновлять каждый раз, когда views изменяется. Но благодаря «буферу изменений» это вряд ли потребует каких-либо дополнительных операций ввода-вывода, по крайней мере сейчас, когда вы выполняете UPDATE.

INT(1) занимает 4 байта; (1) не имеет смысла. Рекомендуется изменить значение на TINYINT (1 байт), сэкономив при этом около 27 байт на строку. (7 столбцов плюс 2 индекса)

country INT(1) - Это флаг? В чем смысл? Нормализовано ли это к другой таблице? Использование 4 байтов для идентификатора и дополнительной таблицы, когда стандартные сокращения («США», «Великобритания», «RU», «IN» и т. Д. c) заняли бы 2 байта? Предлагайте country CHAR(2) CHARACTER SET ascii COLLATE ascii_general_ci.

Индексирование флагов редко приносит пользу. Давайте посмотрим на запросы, где вы думаете, такие индексы могут быть использованы. И EXPLAIN SELECT ... для них.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...