2. За мен
● Веселин Николов
● @dzver
● Работя в Automattic
● PHP, MySQL,
WordPress
3. Работата ми преди
● MS SQL Server 2005
● MySQL < 5.1, 5.1
● 1-2-3 сървъра
● Сложни схеми
● Недостатъчни ресурси
4. Работата ми преди
● Stored Procedures
● Triggers
● SQL Jobs живеещи в DB сървъра
● Конструирани заявки с много случаи
● Materialized Views
● Foreign Keys
● Продължителна замяна на логика с курсори
с логика без курсори
5. Умножете по 1000
● Проблеми с натоварване и много работа по
оптимизиране на сложните заявки
● Денормализация
● Много промени в схемата
7. Шок
● Примитивни заявки, предимно primary key
lookups. Join decomposition.
● Редки и твърде скъпи промени в схемата
● Нови проблеми като replication lag и риск от
чупене услугата
9. Работата ми сега
● MySQL
● Прости заявки
● Огромни обеми заявки
● Множество сървъри
● WordPress
● Memcached
10. Често срещани проблеми
● Много на брой заявки
● Заявки по големи таблици без индекси
● Offsets
● Много сортиране
● Избиране на голям обем данни
11. Често срещани проблеми
● Много на брой заявки
● Заявки по големи таблици без индекси
● Offsets
● Много сортиране
● Избиране на голям обем данни
12. Много на брой заявки
● Нещо много навътре в кода вика не-
кеширана заявка.
13. Решения
● WordPress Debug Bar
https://wordpress.org/plugins/debug-bar/
● WordPress Options API
http://codex.wordpress.org/Options_API
● Caching
wp_cache_set, wp_cache_get
14. Debug Bar
● В тестова среда показва всички заявки
● Може да показва и всички hooks, remote
requests, memcached stats etc.
15. Log
● MySQL Slow Log вече поддържа 0 сек
● Може да се ползва pt-query-digest
● SHOW FULL PROCESSLIST
● SHOW PROFILE
● MS SQL има безкрайно удобен
профайлър :-)
16. Options API
● Таблица с keys и values
● Кеширана е като 1 масив за blog
● Масивът се съхранява в глобална
променлива (чрез object cache)
● Инвалидация на кеша при set/add/delete
=> 1 заявка на много хиляди requests
17. Кеширане
● Не е нужно да се кешира всичко
● Има много нива на кеширане
- Object Cache
- Query Cache
- Memcached
- Batcache
И понякога денормализация
18. Кеширане. MySQL Query Cache
Query Cache = 0
● Кешът се инвалидира при всеки insert/update
● Овърхедът често е по-голям от ползите
● В някои случаи е полезен, но в рамките на
„десетки мегабайти“.
19. Кеширане. Batcache
WordPress plugn за съхраняване на цели
страници в Memcache или APC
● http://evansolomon.me/notes/faster-wordpress-multisite-nginx-batcache/
● https://wordpress.org/plugins/batcache/
● http://xkcd.com/908/
20. wp_cache_get, object cache
● wp_cache_get, wp_cache_add, wp_cache_set,
wp_cache_delete
● Object Cache за избягване на повторни
обръщения към Memcahce
21. Често срещани проблеми
● Много на брой заявки
● Заявки по големи таблици без индекси
● Offsets
● Много сортиране
● Избиране на голям обем данни
22. Липса на индекс
ALTER `table` ADD index ..
Всеки сложен проблем има едно просто решение,
което обикновено е грешно.
23. Липса на индекс
● Индексите са скъпи
● Обновяването им натоварва сървъра
● Поддържането им в паметта е скъпо
● Допълнителен овърхед за query optimizer
● Не е голяма беля, ако не се събират в
паметта.
24. Често срещани проблеми
● Много на брой заявки
● Заявки по големи таблици без индекси
● Твърде много индекси
● Offsets
● Много сортиране
● Избиране на голям обем данни
25. Липса на индекс - решения
● Употреба на прости заявки
● Отбягване на комплексни JOINs
● EXPLAIN SELECT преди commit
● Primary Key само по `id`
данните са клъстърирани по PK, употреба на
комплексен PK може да е полезна в някои приложения
26. Липса на индекс
For join queries, the number of possible plans
investigated by the MySQL optimizer grows
exponentially with the number of tables
referenced in a query.
http://dev.mysql.com/doc/refman/5.7/en/controlling-query-plan-evaluation.html
27. Малко за индексите
При индекси върху повече от 1 поле, редът
има значение:
INDEX foo(A, B, C)
● WHERE A = 3
● WHERE A = 3, B = 4, C = 5
● WHERE B = 5, C = 7
28. Често срещани проблеми
● Много на брой заявки
● Заявки по големи таблици без индекси
● Твърде много индекси
● Offsets
● Много сортиране
● Избиране на голям обем данни
31. Offsets
Прости решения:
SELECT * FROM ...
WHERE `id` > 1093029 LIMIT 20
SELECT * FROM ...
WHERE `ts` BETWEEN '2014-04-11' AND
...
32. Offsets
Сложно решение:
SELECT * FROM `table` JOIN (
SELECT `id` FROM `table`
ORDER BY `whatever`
LIMIT 5000,50
) as `b` USING `id`
33. Често срещани проблеми
● Много на брой заявки
● Заявки по големи таблици без индекси
● Offsets
● Много сортиране
● Избиране на голям обем данни
34. Сортиране
Using filesort; Using temporary;
● Не е rocket science
● Сортиране по индексирана колона
● Индексът е подреден
● Ако подходящ индекс за вашата заявка,
сървърът ползва filesort
35. Сортиране
SELECT * FROM `table`
WHERE A = 3 ORDER BY B
...
ORDER BY A DESC, B DESC
За такава заявка е нужен индекс по A, B (в
този ред)
36. Още малко за индекси...
INDEX(A,B) няма да се ползва при:
● WHERE A > 5 ORDER BY B
● WHERE 1=1 ORDER BY B
● ORDER BY A DESC, B ASC
http://www.percona.com/files/presentations/WEBINAR-MySQL-Indexing-Best-Practices.pdf
37. Antipattern
● ORDER BY RAND()
:
WHERE ID IN (5, 14, 33)
WHERE ID > %d LIMIT 1
shuffle();
38. Antipattern
Употребата на функции в заявките прави
безполезен Query Cache
SELECT * FROM `table`
WHERE my_date = current_date()
SELECT * FROM `table`
WHERE my_date = '2014-05-19'
39. SELECT на много данни
● Cronjobs, one-time scripts
● Вътрешно паджиниране по ID
● Работа с блокове от по 100-1000 записа
40. WordPress.com специфики
● 500 000 000+ таблици
● 600+ DB сървъра
● Master/Slave, partitions, shards, често
таблиците са на различни сървъри
● HyperDB to rule them all
41. HyperDB
● HyperDB е мощен DB клас
● Поддаржа репликация
● Парсва заявките, за да открие към кои
сървъри да се закачи
● Поддържа read и write servers
● Поддържа partitions
42. HyperDB
● Обичайно чете от slaves (read servers)
● Винаги пише в masters
● При UPDATE/INSERT преминава към master
сървър за дадената таблица
43. Replication Lag
● Мастър сървърът получава заявка
● Заявката се записва в бинлог
● Заявката се изпълнява на мастъра
● Слейвът създава thread, който се закача към
мастъра и изисква новите заявки
● Мастърът създава binlog dump за всеки слейв
● Слейв сървърът изпълнява заявките
http://barry.wordpress.com/2011/07/20/hyperdb-lag-detection/
44. Replication Lag
Много неща могат да се счупят:
● Слейвът може да не може да изпълни заявките със
същата скорост
● Бавни заявки на слейва или explicit locks могат да
принудят нишката, която синхронизира да чака
● Бавните заявки на мастъра ще са все така бавни и
на слейва
● Disk I/O, Network issues
45. Replication Lag
Защо е лошо:
● Възможно е да се прочетат стари данни
● Възможно е да се запишат стари данни
● HyperDB знае кои сървъри са лагнати, но
това не ни спасява да мислим заявките си.
46. WordPress.com специфики
● Предпочитаме голямо количество малки
заявки пред малко количество големи
● Таблиците може да не се виждат една друга
в текущия connection на HyperDB
● Рядко ползваме JOINS
47. WordPress.com специфики
● Употребата на дебели JOINS във вашия
проект може да е оправдана
● Избягвайте correlated subqueries
● Ако базата данни поддържа
материализирани изгледи, why not?
(CouchDB, MS SQL, PostgreSQL)
48. Joins...
● Полетата, които се ползват в ON / USING
трябва да са с индекси
● GROUP BY / ORDER BY трябва да са по
една таблица
● Ползвайте JOIN вместо всякакви форми на
subquery
49. Търсене
● LIKE '%foo%' - лоша идея.
● LIKE 'foo%' - възможен индекс
● MATCH ( name ) AGAINST ( 'foo' ) - Full Text
Search (поддържа се от MyISAM и InnoDB
MySQL 5.6+)
● SphinxSearch, Lucene, Solr, ElasticSearch