Окт 26

Для тех, кто не знает, что это такое – ссылка
Вкратце: созздаёт, фактически, «временную таблицу» (более правильно сказать – виртуальную таблицу или результат выборки в виде таблицы), в которой могут храниться данные из других таблиц и результаты применения аггрегирующих функций к ним. При этом если хранятся только данные, то эта таблица обновляется при обновлении входящих в её состав таблиц.
Но оказывается, что, как и многие нововведения (хранимые процедуры должны перекомпилироваться заново при начале сессии, если использовать подзапросы – очень много запросов получается), это тоже имеет очень большие проблемы с производительностью (ссылка).
Вкратце:
неудобно искать проблемы в запросах (вроде как обращаешься к одной таблице, а на деле – нет), создаётся временная таблица без индексов. Также есть проблемы у mySQL при оптимизации запросов при обращении к VIEW.

Теги:
Окт 19
SELECT
  t.TABLE_SCHEMA AS `db`, t.TABLE_NAME AS `table`, s.INDEX_NAME AS `index name`
 , s.COLUMN_NAME AS `field name`, s.SEQ_IN_INDEX `seq in index`, s2.max_columns AS `# cols`
 , s.CARDINALITY AS `card`, t.TABLE_ROWS AS `est rows`
 , ROUND(((s.CARDINALITY / IFNULL(t.TABLE_ROWS, 0.01)) * 100), 2) AS `sel %`
FROM INFORMATION_SCHEMA.STATISTICS s
 INNER JOIN INFORMATION_SCHEMA.TABLES t
  ON s.TABLE_SCHEMA = t.TABLE_SCHEMA AND s.TABLE_NAME = t.TABLE_NAME
 INNER JOIN (
  SELECT TABLE_SCHEMA, TABLE_NAME, INDEX_NAME, MAX(SEQ_IN_INDEX) AS max_columns
  FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA != 'mysql'
  GROUP BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME
 ) AS s2
 ON s.TABLE_SCHEMA = s2.TABLE_SCHEMA AND
    s.TABLE_NAME = s2.TABLE_NAME AND
    s.INDEX_NAME = s2.INDEX_NAME
WHERE t.TABLE_SCHEMA != 'mysql'       /* Filter out the mysql system DB */
AND t.TABLE_ROWS > 10                 /* Only tables with some rows */
AND s.CARDINALITY IS NOT NULL         /* Need at least one non-NULL value in the field */
AND (s.CARDINALITY / IFNULL(t.TABLE_ROWS, 0.01)) < 1.00 /* unique indexes are perfect anyway */
ORDER BY `sel %`, s.TABLE_SCHEMA, s.TABLE_NAME          /* DESC for best non-unique indexes */
LIMIT 10;

Это из лекции товарища Jay Pipes

Теги:
Сен 24

оригинал; полная цитата:
Сегодня был неожиданно удивлен, какие удобные штуки таит в себе MySQL.

Хочу представить вашему вниманию фичу MySQL — профайлинг.
Появилась она начиная с версии 5.0.37.

Всего парой запросов можно узнать, какими запросами формируется страница (для веб-девелоперов)
и почему она тормозит.

И раньше подобный функционал был доступен, но пользоваться журналом запросов не в пример сложнее.

Итак, как пользоваться:

mysql> set profiling=1;
mysql> select count(*) from comment;
mysql> select count(*) from message;
mysql> show profiles;

+———-+————+——————————+
| Query_ID | Duration | Query |
+———-+————+——————————+
| 1 | 0.00012700 | select count(*) from comment |
| 2 | 0.00014200 | select count(*) from message |
+———-+————+——————————+
2 rows in set (0.00 sec)

Вуаля! Все выполненные запросы за сессию с временем выполнения.

На мой взгляд очень просто и сверх-удобно.

Можно пойти дальше, и узнать подробно на что тратилось время по каждому запросу:

mysql> show profile for query 1;
+——————————–+———-+
| Status | Duration |
+——————————–+———-+
| starting | 0.000015 |
| checking query cache for query | 0.000021 |
| checking permissions | 0.000003 |
| Opening tables | 0.000007 |
| System lock | 0.000004 |
| Table lock | 0.000023 |
| init | 0.000005 |
| optimizing | 0.000005 |
| executing | 0.000025 |
| end | 0.000003 |
| end | 0.000001 |
| query end | 0.000002 |
| storing result in query cache | 0.000003 |
| freeing items | 0.000003 |
| closing tables | 0.000004 |
| logging slow query | 0.000002 |
| cleaning up | 0.000001 |
+——————————–+———-+
17 rows in set (0.00 sec)

Подробнее о профайлинге в статье: Using the New MySQL Query Profiler

Upd: как точно подметил zayceslavshow profiles по умолчанию показывает профили для 15 запросов. Кол-во запрсов можно увеличить с помощью параметра profiling_history_size, но не более чем до 100.

mysql> set profiling=1;
mysql> set profiling_history_size=100;

Теги:
Сен 20

Статья по установке
что такое Cygwin
что такое php-fpm
Забавно то, что при ребилде php постоянно вылазили ошибки с доступом.
Как потом случайно удалось выяснить, дело было в Avira AntiVir.

Теги:
Сен 13

http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

Теги:
Сен 09

Для примеров используем следующие таблицы:

Используемые таблицы

используемые таблицы

1. JOIN.

Полное объединение

Операторы JOIN, INNER JOIN и «,» (запятая) с указанием условий объединения дают пересечение для всех совпадающих значений из условия.

SELECT t1.*, t2.* FROM t1, t2 WHERE t1.i1 = t2.i2
#Аналоги:
SELECT t1.*, t2.* FROM t1 JOIN t2 ON t1.i1 = t2.i2
SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ON t1.i1 = t2.i2

В результате получим:
mysql_multiselect_2
При этом если не указать для оператора «,» (запятая) условие выборки WHERE, то получим полное декартово произведение (пересечение каждой строки из первой таблицы с каждой строкой из второй):
mysql_multiselect_1_1
(аналогичный результат получается при использовании CROSS JOIN)
INNER JOIN можно представить как декартово произведение таблиц, из которого потом отобрали только те строки, которые удовлетворяют условию ON, хотя на практике, конечно, используются более совершенные алгоритмы, такие как Hash join и Self-merge join, поскольку алгоритм декартова произведения очень неэффективен.

LEFT JOIN, RIGHT JOIN

При использовании оператора LEFT JOIN выбираются все значения из левой таблицы, после чего к ним подбираются соответствующие значения из правой, если таких нет, то все значения для правой таблицы в этой строке равны NULL.
RIGHT JOIN противоположен LEFT JOIN: всё абсолютно так же, но выбираются все значения для правой таблицы из выражения.

SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON t1.i1 = t2.i2

В результате получим:

результаты LEFT JOIN

результаты LEFT JOIN

SELECT t1.*, t2.* FROM t1, t2 ON t1.i1 = t2.i2
#другая запись
SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ON t1.i1 = t2.i2 WHERE
#аналогично по результату, хотя обычно медленнее
SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON t1.i1 = t2.i2 WHERE t2.i2 IS NOT NULL

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

SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON t1.i = t2.i
#аналогично
SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 USING(i)

JOIN‘ы можно комбинировать:

SELECT t1.*, t2.*
FROM t1, t2
LEFT JOIN t3
ON t1.i = t3.i1 AND t2.i = t3.i2
WHERE t3.i2 IS NOT NULL
Self-join

Self-join объединяет таблицу саму с собой. Проще показать на примере.
Допустим есть таблица

Таблица Employee


И допустим, что нужно получить пары сотрудников, которые работают в одной стране. Результата можно добиться и уже описанными join’ами, но эффективнее будет следующий запрос:

SELECT F.EmployeeID, F.LastName, S.EmployeeID, S.LastName, F.Country
FROM Employee F, Employee S
WHERE F.Country = S.Country
AND F.EmployeeID < S.EmployeeID
ORDER BY F.EmployeeID, S.EmployeeID;

В результате получим:

Результат self-join таблицы Employee


В данном случае:
F и S - алиасы таблицы Employee
условие F.Country = S.Country исключает из результата пары, для которых страны не совпадают
условие F.EmployeeID < S.EmployeeID исключает пары с одинаковыми EmployeeID, а также дублирование ранее выведенных пар (т.е. сотрудник с EmployeeID=145 не выведется слева).

INNER JOIN в некоторых случаях значительно быстрее, чем OUTER JOIN (LEFT JOIN или RIGHT JOIN), поэтому лучше по возможности использовать INNER JOIN. Пример сравнения производительности с объяснением.
Виды JOIN'ов

2. Подзапросы.

Подзапросы организуются в виде вложенных SELECT'ов.
В принципе, в подзапросах можно использовать и другие операторы, но модифицирующие INSERT, REPLACE, DELETE, UPDATE при этом не могут модифицировать таблицу из основного запроса.

SELECT t1.*FROM t1 WHERE t1.i1 IN (SELECT i2 FROM t2 WHERE c2 = 'a')

Подзапрос может возвращать одно значение (скалярный подзапрос), несколько значений одного столбца, несколько значений нескольких столбцов (фактически, таблицу).
Со скалярным подзапросом можно использовать операторы сравнение ("=", ">", "<", "<>" и т.д.).
Приэтом важно, чтобы подзапрос возвращал только одно значение.
Это очень удобно в запросах типа

#так писать нельзя, т.к. значение MIN(i) неизвестно
#до того момента, как произойдёт выборка
#т.е. уже после того, как понадобится "WHERE"
SELECT * FROM t1 WHERE i = MIN(i)
#а вот так писать можно
SELECT * FROM t1 WHERE i = (SELECT MIN(i) FROM t1)

Если подзапрос возвращает одну строку, то можно использовать кортеж (набор значений для сравнения):
Это очень удобно в запросах типа

SELECT t1.* FROM t1
WHERE (i, c) = (SELECT i, c FROM t2 WHERE i = 2 LIMIT 1)

Если подзапрос может вернуть несколько значений, то лучше ипользовать операторы IN и NOT IN вместо = и <> соответственно.

SELECT t1.* FROM t1
WHERE (i, c) IN (SELECT i, c FROM t2)

Операторы EXISTS и NOT EXISTS нужны для того, чтобы определить, вернулись ли значения из подзапроса (используются для коррелированных подзапросов).

SELECT * FROM t1
WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE i > 10000)
Коррелированные подзапросы

содержат ссылки на значения внешнего запроса.

SELECT i FROM t1 WHERE j IN (SELECT k FROM t2 WHERE k = i)

Пример несколько странный получился.
Более реалистичный:

SELECT i FROM t1
WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.i1 = t1.i)

Подзапросы можно переписывать через операторы JOIN (в некоторых случаях может работать быстрее).

SELECT * FROM t1
WHERE i IN (SELECT i1 FROM t2 WHERE t2.i = 15)
#аналогично
SELECT t1.* FROM t1, t2
WHERE t1.i = t2.i1 AND t2.i = 15

* При этом могут возвращаться несколько разные результаты, если в t2.i1 содержатся неуникальные значения. В таком случае подзапрос выдаст только уникальные значения, а JOIN выдаст все. Чтобы этого избежать, нужно во втором запросе использовать оператор SELECT DISTINCT (выбрать только уникальные значения).

SELECT * FROM t1
WHERE i NOT IN (SELECT i1 FROM t2)
#аналогично
SELECT t1.*
FROM t1 LEFT JOIN t2 ON t2.i1 = t1.i
WHERE t2.i1 IS NULL

(при этом в подзапросе можно заметить отсутствие условия выборки;))

3. UNION

Выборка из нескольких таблиц последовательно.
UNION действует как SELECT DISTINCT, т.е. отбрасывает повторяющиеся значения. чтобы этого избежать, нужно использовать оператор UNION ALL

(SELECT i, c FROM t1 ORDER BY i DESC)
UNION
(SELECT i, d FROM t2 ORDER BY i)
Теги:
Сен 06

при переустановке windows можно обойтись без переустановки apache, mysql и php
Continue reading »

Теги:
Авг 11

Случайно наткнулся на комментарий, что привело меня к инструменту MySQL Performance Tuning (ещё ссылка, tuning-primer – сам скрипт) для оптимизации mySQL путём советов по изменению конфига на основе логов.

Теги:
preload preload preload