Примеры
Прежде чем изучать использование внутренних объединений, мы можем получить результат из двух разных таблиц на основе условий, используя оператор SELECT и предложение WHERE. В следующем примере «books» и «authors» – это две разные таблицы в базе данных.
DESC books; DESC authors;
В таблице “books” у нас есть внешний ключ author_id из таблицы “authors”.
Чтобы получить все столбцы из обеих таблиц, мы устанавливаем books.author_id = developers.author_id. Запрос SELECT будет следующим:
SELECT * FROM books, authors WHERE books.author_id = authors.author_id;
Как вы можете видеть на изображении выше, мы получили все столбцы из обеих таблиц. Часто иметь все столбцы нецелесообразно, даже если они не нужны. Итак, если вы хотите получить только определенные столбцы из обеих таблиц, вам нужно будет указать имена столбцов в операторе SELECT, как показано ниже:
SELECT books.book_name, books.category, authors.author_fname, authors.author_lname FROM books, authors WHERE books.author_id = authors.author_id;
Как видите, у нас есть чистый и четкий вывод четырех столбцов из обеих таблиц.
Теперь мы выполним ту же задачу, используя предложение INNER JOIN.
Чтобы объединить две таблицы с помощью предложения INNER JOIN, запрос SELECT будет следующим:
SELECT books.book_name, books.category, authors.author_fname, authors.author_lname FROM books INNER JOIN authors ON books.author_id = authors.author_id;
Как вы можете видеть на скриншоте выше, мы получили тот же результат, но на этот раз с использованием предложения INNER JOIN.
Как указывалось ранее, предложение INNER JOIN такое же, как простое предложение JOIN. Это означает, что мы можем использовать предложение JOIN вместо предложения INNER JOIN и по-прежнему получать те же результаты. Запрос SELECT с простым предложением JOIN будет выглядеть следующим образом:
SELECT books.book_name, books.category, authors.author_fname, authors.author_lname FROM books JOIN authors ON books.author_id = authors.author_id;
Как вы можете видеть на изображении выше, мы получили те же результаты. Это показывает, что простые предложения JOIN и INNER JOIN одинаковы. Вы можете получить те же результаты, используя любое из этих предложений соединения.
Концепция внутреннего соединения на этом не заканчивается. В предыдущих примерах мы применили объединение двух таблиц на основе ключа author_id. Поскольку мы знаем, что ключ author_id уже является внешним ключом в таблице «books», мы можем сократить синтаксис, используя предложение USING с соединением. Синтаксис использования предложения USING с предложением JOIN следующий:
SELECT books.book_name, books.category, authors.author_fname, authors.author_lname FROM books JOIN authors USING (author_id);
Можно заметить, что этот запрос дал те же результаты с предложением USING.
Точно так же мы можем применить условие вместе с применением соединения между двумя таблицами, используя предложение WHERE. Например, чтобы получить те же четыре столбца из обеих таблиц, в которых фамилия автора равна ‘Master’, запрос на получение такого вывода будет следующим:
SELECT books.book_name, books.category, authors.author_fname, authors.author_lname FROM books JOIN authors USING (author_id) WHERE authors.author_lname = 'Master';
Как вы можете видеть на изображении выше, мы получили только две строки, в которых фамилия автора – «Master».
Итак, теперь вы видели несколько примеров различных способов использования внутреннего соединения для получения желаемых результатов в MySQL.
MySQL sleep() injection attacks, the conclusion
This post showed you the importance of validating user supplied input. The lack of input validation (Dutch article) not only makes your website vulnerable to SQL injection attacks (Dutch article) or Cross Site Scripting (XSS – Dutch article), but may also make your web server and/or MySQL database server unresponsive due to these MySQL command injections.
This’ll disrupt the service, not only for your website, but for all users on the same web server and MySQL database server. Especially when a new MySQL vulnerability is found that crashes the MySQL service, like MySQL DoS in the Procedure Analyse Function – CVE-2015-4870.
You wouldn’t want to be the one who crashed aan entire database server just because you didn’t validate user supplied input, now would you?
Дополнительная информация
Важно!
В этот раздел, описание метода или задачи включены действия, содержащие указания по изменению параметров реестра. Однако неправильное изменение параметров реестра может привести к возникновению серьезных проблем. Поэтому следует в точности выполнять приведенные инструкции. Для дополнительной защиты создайте резервную копию реестра, прежде чем редактировать его. Так вы сможете восстановить реестр, если возникнет проблема. Дополнительные сведения о том, как создать и восстановить реестр, см. в дополнительных сведениях о том, как создать и восстановить реестр в окне.
Возможно, вам придется увеличить значение времени ожидания по умолчанию для постоянных подключений HTTP в Internet Explorer, если вы используете веб-программу, которая должна общаться с Internet Explorer через тот же TCP/IP-розет после одной минуты простоя. Чтобы изменить значение времени ожидания по умолчанию для сохраняющихся подключений HTTP в Internet Explorer, добавьте значение DWORD, названное в следующем ключе реестра, а затем установите его данные значения до времени (в миллисекунд), которое необходимо подождать internet Explorer перед сбросом простоя подключения:
Чтобы изменить значение времени по умолчанию для постоянных подключений HTTP в Internet Explorer, выполните следующие действия:
-
Щелкните Пуск, затем Выполнить и введите regedit. Затем нажмите ОК.
-
Найдите и нажмите следующий ключ в реестре:
-
В меню Правка выберите пункт Создать, а затем Параметр DWORD.
-
Введите KeepAliveTimeout и нажмите кнопку ENTER.
-
В меню Правка щелкните Изменить.
-
Введите соответствующее значение времени (в миллисекунах), а затем нажмите кнопку ОК. Например, чтобы установить значение времени до двух минут, введите 120000 .
-
Перезапуск браузера Internet Explorer Если значение не превышает 60 000 (одна минута), могут возникнуть проблемы с общением с веб-серверами, которые требуют постоянных подключений HTTP. Например, вы можете получить сообщение об ошибке, которое не отображается на странице.
Если у вас должно быть значение выше 120000 (две минуты), необходимо создать дополнительный ключ реестра и установить его значение, равное нужному значению. Дополнительный ключ реестра . Это DWORD со значением (в миллисекунах) и в том же расположении, что и .
Например, чтобы использовать трехминутное значение, необходимо создать следующие клавиши реестра:
По умолчанию HTTP 1.1 включен в Internet Explorer, за исключением случаев, когда вы устанавливаете подключение http через прокси-сервер. При включении HTTP 1.1 подключения HTTP остаются открытыми (или настойчивыми) по умолчанию, пока подключение не будет простаивать в течение одной минуты или до тех пор, пока не будет достигнуто значение, указанное значением в реестре. Параметры HTTP 1.1 можно изменить в Internet Explorer с помощью вкладки Advanced в диалоговом окне Параметры Интернета.
[3] Исключение проекта и настройка значения
В проекте используется программа для подключения к базе данных, поэтому она относится к неинтерактивному соединению, и вам необходимо сосредоточиться на том, как установить значение wait_timeout.
Общие проблемы заключаются в следующем:
① The last packet successfully received from the server was 23,579 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago. Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
② MySQL server has gone away
Настройка значения
Значение по умолчанию wait_timeout составляет 28800, и размер должен быть определен в соответствии с проектом. Wait_timeout слишком велик и имеет свои недостатки. Его проявлением является то, что большое количество процессов SLEEP в MySQL не может быть выпущено вовремя. Если он слишком мал, легко столкнуться с такими проблемами, как отключение сервера MySQL и ожидание тупика.
Investigating PHP/MySQL sleep() attacks
The other day I noticed several hung queries (SELECT statements) on one of the MySQL database servers under my control. All hung queries had in common they were running for a very long time. And, showed a command in the query.
Given the casing of the MySQL sleep command (“SLeeP”), this was obviously done by an sql injection tool of some kind. I could simply kill the MySQL queries and threads and be done with it, but I wanted to be sure this MySQL sleep() attack couldn’t happen again.
After killing the MySQL threads I took a quick look at the website. Given I had both the executed query and website HTTP log files available for my investigation, I quickly located the vulnerable PHP script.
The vulnerable line of PHP code was:
Where was directly used in a MySQL query.
Did you notice the lack of input validation? As long as is provided in the URL, it’s not set to 0. Through my browsers address bar I can add to the URL, to make this query hung, on the server for quite some time.
The MySQL command is executed for every record the query finds. The website’s PHP code doesn’t use prepared statements, I checked.
Because it’s not my PHP code or website, I informed the creator about this vulnerability in his code, and the lack of input validation. Until it’s fixed, I’ll keep a close watch on this website and database. It may not surprise you that I find more and more of these SQL injection and MySQL sleep() attacks lately.
Securing the vulnerable PHP code
In the piece of PHP code above, is easily made more robust and secure by adding :
This will make PHP to cast the input value into an integer, this is called Type Juggling or Type Casting. The name of the desired type is written in parentheses before the variable which is to be cast. Of course the customer using this code needs to update the PHP functions to use MySQLi or PDO, e.g. migrate from mysql_connect to mysqli_connect.
And further is the use of Prepared Statements and/or Stored Procedures important.
Kill multiple MySQL threads at once
Protip: If you need to kill multiple connection threads in MySQL, you can use the following command to generated a comma separated list of connection id’s and kill them with :
This uses mysqladmin and some bash commands to built a comma separated list of connection ID’s, that you can copy and paste into mysqladmin kill.
Or you can kill all threads using mysql’s command interface and a query:
(thank you mysqlperformanceblog.com for this query)
Ошибка 2006: MySQL server has gone away
Ошибка MySQL server has gone away означает, что сервер закрыл соединение, что происходит, как правило, в двух случаях: превышение таймаута ожидания или получение сервером слишком большого пакета.
Конфигурационный файл может располагаться по различным путям, например:
/etc/my.cnf /etc/mysql/my.cnf /etc/mysql/mysql.conf.d/mysqld.cnf
Чтобы определить, в какой файл необходимо вносить изменения, можно использовать команду вида:
grep -Rl 'имя_параметра' /etc/* # Например: grep -Rl 'wait_timeout' /etc/* # или: grep -Rl 'max_allowed_packet' /etc/*
С ее помощью можно выяснить, в каких файлах прописан интересующий нас параметр, и изменить в них его значение.
Таймаут
Чтобы увеличить таймаут ожидания, необходимо скорректировать значение параметра .
Откройте конфигурационный файл с помощью редактора (укажите корректный путь к файлу):
nano /etc/mysql/my.cnf
Измените значение параметра wait_timeout на более высокое. Значение указывается в секундах, т.е. чтобы увеличить время ожидания, например, до 10 минут, необходимо указать 600:
wait_timeout = 600
После перезапустите службу MySQL:
# Debian / Ubuntu service mysql restart # CentOS service mysqld restart
Размер пакетов
В этом случае можно скорректировать максимально допустимый размер пакетов, увеличив параметр .
Откройте файл конфигурации (укажите корректный путь к файлу):
nano /etc/mysql/my.cnf
Измените значение параметра max_allowed_packet на более высокое (значение указывается в мегабайтах):
max_allowed_packet = 64M
И перезапустите службу:
# Debian / Ubuntu service mysql restart # CentOS service mysqld restart
[2] Наследование
Separately Изменить глобальное интерактивное время ожидания отдельно
Просмотрите значения глобальной переменной и переменной сеанса отдельно:
проанализировать, как показано ниже:
В интерактивном режиме interactive_timeout на сеансовом и глобальном уровнях наследует значение global_timeout global. Значение wait_timeout уровня сеанса наследует interactive_timeout. Время ожидания на глобальном уровне не затрагивается.
② Установить уровень сеанса
проанализировать, как показано ниже:
Независимо от того, влияет ли значение атрибута interactive_timeout на глобальном уровне или на уровне сеанса wait_timeout.
③ Установите глобальное значение одновременно и разные
Просмотр значений глобальной переменной:
Просмотр значений переменных сеанса:
проанализировать, как показано ниже:
Wait_timeout на уровне сеанса наследует значение interactive_timeout на глобальном уровне. Время ожидания на глобальном уровне не затрагивается. Не изменяя значение interactive_timeout, измените значение wait_timeout, результат недействителен.
Выше приведен результат теста интерактивного соединения: wait_timeout интерактивного соединения наследуется от глобального interactive_timeout.
Результат неинтерактивного подключения выглядит следующим образом: wait_timeout неинтерактивного подключения наследуется от глобального wait_timeout.
Как ускорить чтение
Допустим, диски загружены запросами на чтение. Что можно сделать, чтобы ускорить отдачу данных? Закэшировать данные в памяти. MySQL предоставляет возможность использования разных хранилищ, или движков (storage engines), для доступа к данным, поэтому подход к кэшированию разный. Рассмотрим два наиболее популярных движка: MyISAM и InnoDB.
Движок InnoDB имеет встроенный кэш для данных и индексов — так называемый Buffer Pool. Его размер регулируется переменной innodb_buffer_pool_size. В идеале размер Buffer Pool должен быть как минимум такого объёма, чтобы в нём полностью можно было разместить все данные и индексы плюс 30%-60% от их размера. Дополнительная память используется для служебных нужд и Insert Buffer, а также для обеспечения запаса памяти на будущее. Переменная innodb_buffer_pool_size — не динамическая, поэтому после её изменения в конфигурационном файле потребуется перезапуск MySQL.
Движок MyISAM не имеет кэша для данных. Но мы по-прежнему можем ускорить чтения из таблиц MyISAM. Дело в том, что ядро Linux кэширует все прочитанные файлы в области оперативной памяти, которая называется pagecache. Разумеется, файлы с таблицами MyISAM также попадают в этот кэш. Объём pagecache можно узнать из вывода команды free:
$ free -m total used free shared buffers cached Mem: 257934 255969 1964 0 4354 157772 -/+ buffers/cache: 93841 164092 Swap: 0 0 0 $
Максимальной производительности чтения можно добиться, если объём pagecache равен объёму данных MyISAM.
По умолчанию под pagecache выделяется почти вся незанятая процессами память, поэтому увеличить его объём можно лишь установкой дополнительных планок RAM. Однако память — недорогой по сравнению с ЦПУ и дисками ресурс, при этом эффект от увеличения кэша может привести к значительному увеличению производительности. Ниже представлен график %iowait — доли времени, в течение которого ЦПУ ожидает ввода/вывода. График снят с рабочего нагруженного сервера. Думаю, комментарии здесь излишни.
7 ответов
Конфигурация тайм-аута для каждого пользователя отсутствует, но вы можете установить значение динамически. То есть после того, как вы установили соединение как данный пользователь, вы можете выполнить инструкцию, чтобы изменить значение тайм-аута на то, что вы хотите, чтобы оно было для сеанса этого пользователя.
Попробуйте выполнить следующий эксперимент в клиенте командной строки mysql:
… показывает 28800 (т.е. 8 часов), что является значением по умолчанию .
… показывает 60.
Затем вы можете выйти из сеанса, повторно подключиться, и снова значение по умолчанию равно 28800. Таким образом, оно ограничено областью действия текущего сессия.
Вы также можете открыть второе окно и запустить отдельный сеанс клиента mysql, чтобы доказать, что изменение в одном сеансе не влияет на другие одновременные сеансы.
Вы должны установить следующие переменные в своем :
— это тайм-аут для автоматических подключений (, на мой взгляд, более 30 на слишком много веб-сервера ). — это время ожидания взаимодействия с консолью для простоя сессии.
Еще одна возможность: MySQL поддерживает две разные переменные тайм-аута: для неинтерактивных клиентов и для интерактивных клиентов.
Разница между интерактивными и неинтерактивными клиентами заключается в том, что при подключении вы указали параметр .
Я не знаю, поможет ли это вам, потому что вам нужно как-то заставить передать эту опцию в параметр. Я не уверен, какой язык или интерфейс вы используете, поэтому я не знаю, позволяет ли вам указать этот флаг подключения.
В любом случае, если вы можете передать этот флаг клиента и вам нужны только два разных типа пользователей, вы можете настроить и —- +: = 6 =: + —- по-разному в конфигурации сервера MySQL, а затем используйте тот, у которого более короткое значение, если вы хотите, чтобы время для данного сеанса истекло. р>
Другие соединители для других языков, вероятно, позволят то же самое.
Я проверил таблицу , и похоже, что для нее нет настроек:
В зависимости от того, используете ли вы MySQLi или PDO, ваши PHP-соединения с MySQL должны либо зависать при выполнении запроса, либо использоваться совместно в пуле для процесса Apache.
Например, с помощью PDO, чтобы отключить постоянные соединения (я думаю, это по умолчанию), подключитесь к вашей БД с помощью:
$ pdo = новый PDO ($ dsn, $ user, $ pass, Array (PDO :: ATTR_PERSISTENT => false));
Если вы хотите, чтобы ваши сценарии использовали постоянные соединения, но у вас слишком много соединений, открытых к вашей базе данных в спящем режиме, вам следует подумать о настройке , , и , чтобы не так уж много людей оставалось без дела.
С помощью pt-kill можно уничтожать соединения для каждого пользователя. Вы можете запланировать это или настроить фоновое задание, чтобы справиться с этим.
init_connect будет выполняться всякий раз, когда пользователь входит в систему, поэтому мы можем написать небольшую инструкцию case и установить значение на основе пользователя
Обратите внимание, что init_connect не будет выполняться для суперпользователя
Ошибка 1292: Incorrect date value
При попытке добавить данные в таблицу MySQL без указания даты может выдаваться ошибка:
ERROR 1292 (22007): Incorrect date value: '0000-00-00' for column 'columnname' at row 1
Из-за этой ошибки может нарушаться работа импорта в 1С.
Для решения проблемы необходимо:
1. Открыть файл
nano /etc/mysql/my.cnf
2. В строке, начинающейся с удалить следующие значения:
NO_ZERO_IN_DATE NO_ZERO_DATE STRICT_ALL_TABLES
3. Выполнить перезагрузку mysql-сервера:
sudo service mysql restart
Примечание:
Если строка вида отсутствует, необходимо:
1. В файл после параметра добавить строку:
sql-mode="ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
2. Выполнить перезагрузку mysql-сервера:
sudo service mysql restart
Как ускорить запись
Увеличить производительность MySQL при большом объёме записи можно с помощью тонкой настройки параметров сервера.
По умолчанию InnoDB сбрасывает изменённые данные на диск с помощью системного вызова fsync(). При этом операционная система не гарантирует, что данные попадут в хранилища сию секунду, т.к. данные сперва проходят через буфер, поддерживаемый ядром. Буферизация необходима для ускорения ввода/вывода.
Однако если datadir MySQL расположен на аппаратном RAID-массиве, то есть возможность задействовать для такой буферизации NVRAM-кэш RAID-контроллера, что намного эффективнее. Следует только убедиться, что контроллер оснащён BBU (Battery Backup Unit) — отдельным источником питания для кэша. При внезапном отключении электропитания у контроллера должно быть время, чтобы сбросить содержимое кэша на диски, иначе данные в массиве останутся в неконсистентном состоянии.
При задействовании кэша RAID-контроллера повысить производительность операций записи в БД можно, отключив ненужную буферизацию на уровне операционной системы. Для этого требуется выставить переменную MySQL innodb_flush_method в значение O_DIRECT, после чего перезагрузить систему управления базы данных. Снизить нагрузку на диски также может изменение переменной innodb_flush_log_at_trx_commit. Для соответствия требованиям ACID движок InnoDB хранит логи транзакций, или redo-логи, в которые записываются все запросы на изменение данных. Эти логи используются в процессе восстановления после аварийного останова системы управления базами данных.
Значение по умолчанию (1) предполагает, что буфер redo-логов, расположенный в памяти InnoDB, записывается на диск после каждого коммита транзакции. Это наиболее безопасный режим работы, обеспечивающий сохранность каждой транзакции даже в случае “падения” сервера. Можно выставить innodb_flush_log_at_trx_commit в значение 2, тогда логи будут записываться также после каждого коммита, но fsync() — сброс данных на диск — будет выполняться лишь раз в секунду (начиная с версии MySQL 5.6.6 этот интервал определяется переменной innodb_flush_log_at_timeout). Аварийное завершение работы СУБД не приведёт к потере транзакций, однако отключение самого сервера может привести к потере последней секунды транзакций. Значение 0 подразумевает ещё более быстрый режим записи — данные и записываются, и синхронизируются раз в секунду, безотносительно коммитов транзакций. Однако innodb_flush_log_at_trx_commit=0 может привести к потере транзакций даже при падении процесса. Администратору базы данных нужно сделать выбор исходя из текущей нагрузки и бизнес-требований.
Оптимизировать дисковые операции записи помогает правильный выбор размера redo-логов. Для этого есть несложное правило. Достаточно замерить объём данных, который записан в лог за одну минуту. Эту операцию нужно выполнять в момент дневной пиковой нагрузки:
mysql> show global status like "Innodb_os_log_written"; select sleep(60); show global status like "Innodb_os_log_written"; +-----------------------+--------------+ | Variable_name | Value | +-----------------------+--------------+ | Innodb_os_log_written | 337936892416 | +-----------------------+--------------+ 1 row in set (0.00 sec) +-----------+ | sleep(60) | +-----------+ | 0 | +-----------+ 1 row in set (1 min 0.01 sec) +-----------------------+--------------+ | Variable_name | Value | +-----------------------+--------------+ | Innodb_os_log_written | 337939448320 | +-----------------------+--------------+ 1 row in set (0.00 sec) mysql> select (337939448320 - 337936892416) / 1024 / 1024 as innodb_log_written_per_min; +----------------------------+ | innodb_log_written_per_min | +----------------------------+ | 2.43750000 | +----------------------------+ 1 row in set (0.00 sec) mysql>
Из примера видно, что за минуту в лог InnoDB записывается 2,44 Мб данных. Объём лога следует подбирать таким образом, чтобы в него умещался объём данных за час. В таком случае у InnoDB будет достаточно времени, чтобы изменить порядок запросов на ввод/вывод для достижения последовательной записи. В нашем примере за один час через redo-логи проходит 150 Мб данных, поэтому переменную innodb_log_file_size следует выставить в значение не менее 75M. Если объём лога выбрать слишком большим, то увеличится время InnoDB Crash Recovery, что увеличит даунтайм при аварийном перезапуске (стоит отметить, что в MySQL 5.5 время Crash Recovery зависит от размера InnoDB-лога в меньшей степени).
MySQL Sleep
I see if frequently with web applications and it is often indication of trouble. Not only it means you may run out of MySQL connections quicker than you expected but it also frequently indicates serious problems in the application. If you do not use persistent connections and you have connection in Sleep stage for 600 seconds what could it be ? It may mean some of your pages take that long to generate (or might be the code simply gets into the tight loop and page never gets generated) it also could mean some of external Web Services are slow or not available and you’re not dealing with timeouts properly. Or may be you have several connections to MySQL server and right now running query which takes that long ? In any case it is something frequently worth looking at.
First task is to find to which process the connection belongs. Using different user names for different application is a good practice however it will not tell you which of apache children is handling request in question. If you just want to fix it, ie by restarting apache it is enough but if you want to figure out why it is happening you need more info.
You may notice in the “Host” filed of SHOW PROCESSLIST output not only host but also port is specified, showing you something like “192.168.1.70:58555” This port can be used to identify the process which owns connection in question:
Shell
# netstat -ntp | grep :45384
tcp 0 0 192.168.1.70:45384 192.168.1.82:3306 ESTABLISHED 28540/php-cgi
1 |
root@w1~# netstat -ntp | grep :45384 tcp192.168.1.7045384192.168.1.823306ESTABLISHED28540/php-cgi |
As you can see in this case we can find php-cgi is holding connection in question (this is lighttpd based system with fastcgi)
Now you know the process and you can use your favorite tools to check what that process is doing.
Shell
# netstat -ntp | grep 28540
tcp 0 0 192.168.1.70:58555 192.168.1.90:11211 ESTABLISHED 28540/php-cgi
tcp 0 0 192.168.1.70:52711 192.168.1.88:8080 ESTABLISHED 28540/php-cgi
tcp 0 0 192.168.1.70:45384 192.168.1.82:3306 ESTABLISHED 28540/php-cgi
tcp 0 0 192.168.1.70:45399 192.168.1.82:3306 ESTABLISHED 28540/php-cgi
tcp 0 0 192.168.1.70:45407 192.168.1.82:3306 ESTABLISHED 28540/php-cgi
tcp 0 0 192.168.1.70:45408 192.168.1.82:3306 ESTABLISHED 28540/php-cgi
tcp 0 0 192.168.1.70:35556 192.168.1.92:11211 ESTABLISHED 28540/php-cgi
1 |
root@w1~# netstat -ntp | grep 28540 tcp192.168.1.7058555192.168.1.9011211ESTABLISHED28540/php-cgi tcp192.168.1.7052711192.168.1.888080ESTABLISHED28540/php-cgi tcp192.168.1.7045384192.168.1.823306ESTABLISHED28540/php-cgi tcp192.168.1.7045399192.168.1.823306ESTABLISHED28540/php-cgi tcp192.168.1.7045407192.168.1.823306ESTABLISHED28540/php-cgi tcp192.168.1.7045408192.168.1.823306ESTABLISHED28540/php-cgi tcp192.168.1.7035556192.168.1.9211211ESTABLISHED28540/php-cgi |
Using same netstat command and filtering on the PID we can find which connections does this process have. Here you can see it has couple of memcached connections. Few MySQL connections (to the same host, which if usually bad idea) and connection to some external web server.
You can use strace -p to see what host is doing, it often gives a clue. In this case I for example found the process is stuck in pool() system call reading from network. Using netstat can give you an idea what it can be but if you do not like guessing you can use gdb -p . It will not print your exact line of code in PHP which is running but can give you some good ideas – for example in this case I could find stack trace originated from php stream functions not from libmysql or memcache.so, which means it is not MySQL or memcache connections leaving last candidate as the only choice. I also could see some of the variables in GDB “bt” command output which also hinted what could be the problem.
By the way does anyone know any debugger which can connect to PHP process or apache with mod_php and provide backtrace in PHP terms not the one for zend engine ? That would be pretty cool.
Yet another great tool which you can use is server-status if you’re running apache. This way you will see the URL which that process is processing and so get few more hints on what may be happening or even get repeatable example in some cases.
The tools I mentioned regarding figuring our what is happening with the process are not only helpful to debug sleeping connections with MySQL but many other cases when you see web application locking up or starting to runs in the tight loop consuming too much CPU time.
If you know any other tools which could be helpful in this regard would appreciate your comments. There might be some smarter tools out where for production tracing.
Повреждены таблицы БД (Table is marked as crashed)
При возникновении ошибок вида «Warning: Table … is marked as crashed» необходимо выполнить восстановление таблиц.
Если на сервере установлен phpMyAdmin, можно выполнить восстановление с его помощью. Для этого перейдите в интерфейс PMA и кликните на нужную базу данных в меню слева. Отметьте в списке те таблицы, которые нужно восстановить (то есть таблицы, имена которых фигурируют в ошибках). В самом низу страницы нажмите на выпадающее меню «С отмеченными» и выберите вариант «Восстановить».
Для восстановления одной таблицы выполните команду:
mysqlcheck -r имя_базы имя_таблицы -uroot -p
Для восстановления всех таблиц в базе используйте:
mysqlcheck -r имя_базы -uroot -p
Вы также можете выполнить проверку всех таблиц в базе с помощью команды:
mysqlcheck -r -A -uroot -p