зеркало из
				https://github.com/iharh/notes.git
				synced 2025-10-31 21:56:08 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			61 строка
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			61 строка
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| https://www.postgresql.org/docs/current/sql-analyze.html
 | |
| 
 | |
| https://public.dalibo.com/exports/conferences/_archives/_2012/201211_explain/understanding_explain.pdf
 | |
| 
 | |
| *************************************************************
 | |
| 1. Обычный EXPLAIN ANALYZE показывает время выполнения, но не всегда объясняет, почему оптимизатор выбрал тот или иной путь. Попробуем расшифровать скрытые подсказки:  
 | |
| 
 | |
| EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT * FROM orders WHERE user_id = 100 AND status = 'processed';
 | |
| 
 | |
| Ключевые параметры:  
 | |
| BUFFERS - об этом параметре мы уже подробно писали (https://t.me/pg_guru/299), показывает, сколько данных было прочитано из кеша/диска;
 | |
| VERBOSE - раскрывает дополнительные детали, например, имена столбцов.  
 | |
| 
 | |
| Если в выводе видим Buffers: shared hit=1534 read=217, это значит, что 1534 страницы были в кеше, а 217 пришлось читать с диска. Оптимизация может заключаться в увеличении work_mem или добавлении индекса, покрывающего запрос, а вовсе не в переписывании текста самого запроса.
 | |
| 
 | |
| 2. PostgreSQL выбирает алгоритм соединения таблиц на основе статистики. Но иногда ей можно помочь и принудительно указать тип JOIN (не всегда рекомендуется!)
 | |
| 
 | |
| SET enable_nestloop = off;
 | |
| SET enable_hashjoin = on;
 | |
| SET enable_mergejoin = off;
 | |
| 
 | |
| Когда что использовать:  
 | |
| Hash Join - хорош для больших несортированных таблиц;
 | |
| Merge Join - эффективен, если данные уже отсортированы (например, по индексу);
 | |
| Nested Loop - лучший выбор для маленьких таблиц или когда одна из них сильно фильтруется.  
 | |
| 
 | |
| 3. Вместо создания индекса на весь столбец можно оптимизировать место и использовать частичные или покрывающие индексы. Про такие виды индексов мы более подробно уже писали (https://t.me/pg_guru/666).
 | |
| 
 | |
| Частичный индекс (только для "активных" заказов):
 | |
| 
 | |
| CREATE INDEX idx_orders_active ON orders (user_id) 
 | |
| WHERE status = 'active';
 | |
| 
 | |
| Покрывающий индекс:
 | |
| 
 | |
| CREATE INDEX idx_orders_covering ON orders (user_id) INCLUDE (status);
 | |
| 
 | |
| Если запрос запрашивает только user_id и status, PostgreSQL может выполнить Index Only Scan, вообще не обращаясь к таблице.  
 | |
| 
 | |
| 4. Работа с JSONB может быть медленной без правильных индексов.
 | |
| 
 | |
| Создаём GIN-индекс для быстрого поиска по ключам:
 | |
| 
 | |
| CREATE INDEX idx_gin_data ON users USING gin (profile_data);
 | |
| 
 | |
| Мы можем создать индекс по конкретному JSON пути:
 | |
| 
 | |
| CREATE INDEX idx_jsonb_path ON users 
 | |
| USING gin ((profile_data->'address'->>'city'));
 | |
| 
 | |
| Теперь запросы вроде  
 | |
| 
 | |
| SELECT * FROM users 
 | |
| WHERE profile_data @> '{"address": {"city": "Moscow"}}';
 | |
| 
 | |
| будут работать гораздо быстрее.  
 | |
| 
 | |
| На этом пока все! Будем развивать данную тему в будущих постах.
 | |
| 
 | |
| Если у вас есть какие-то лайфхаки по оптимизации запросов в PostgreSQL, оставляйте их в комментариях. До связи!
 | 
