но кеш импакт не влияет на рейс если он не рекомый. а тогда как вы объясните кучерявость запроса? каждый рейс нужно кешировать чтобы он стал рекомый, иначе будет старвейшн, но смотрите чтоб не начался кеш компакшн. иначе без второй забивки, точно будет не разобрать. или как вариант побрить запрос, чтобы он стал лысый. аэродинамика лысой головы лучше. но это крайняя мера. это если скучно заживется.
LazyBadger, вы сначала ответьте на
При всем уважении, я знаю что такое race conditions, но вашу фразу в упор понять не могу, что конкретно вы имели ввиду, в контексте баз данных и кеширования? И значит кроме отдельных race conditions?
SELECT COUNT(*) это для того, чтобы вы поняли что тут далеко не 2к артикулов как у тс, а в 1600 раз больше, я думал вы поймете что это не основной запрос, как минимум из плана выполнения, который я скинул))
Всего артикулов в базе: 3204349
Выборка товаров по критериям:
Бренд: Xiaomi, Samsung, LG, Huawei
CPU: 2,
RAM: 2048, 4096
Выполнение: 6-10 мс.
QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=2.57..547.25 rows=30 width=45) (actual time=0.238..6.094 rows=30 loops=1) -> Nested Loop (cost=2.57..2420214.72 rows=133303 width=45) (actual time=0.237..6.084 rows=30 loops=1) -> Nested Loop Semi Join (cost=2.15..2360638.33 rows=133303 width=38) (actual time=0.228..5.927 rows=30 loops=1) -> Nested Loop (cost=1.72..2148113.35 rows=462054 width=86) (actual time=0.101..5.401 rows=121 loops=1) -> Nested Loop (cost=1.29..1934033.44 rows=462055 width=54) (actual time=0.092..4.839 rows=121 loops=1) -> Nested Loop (cost=0.86..1558868.91 rows=806425 width=38) (actual time=0.082..3.734 rows=207 loops=1) -> Index Scan using shop_product_sku_offer_price_idx on shop_product_sku_offer spso (cost=0.43..94254.38 rows=3204341 width=22) (actual time=0.026..0.704 rows=780 loops=1) -> Index Only Scan using shop_feature_cores_sku_pkey on shop_feature_cores_sku sfcs (cost=0.43..0.46 rows=1 width=16) (actual time=0.004..0.004 rows=0 loops=780) Index Cond: ((sku_id = spso.sku_id) AND (feature_value_code = 2)) Heap Fetches: 0 -> Index Scan using shop_feature_brand_sku_pkey on shop_feature_brand_sku sfbs (cost=0.43..0.47 rows=1 width=16) (actual time=0.005..0.005 rows=1 loops=207) Index Cond: (sku_id = spso.sku_id) Filter: (feature_value_code = ANY ('{xiaomi,samsung,lg,huawei}'::text[])) Rows Removed by Filter: 0 -> Index Scan using shop_product_sku_pkey on shop_product_sku sps (cost=0.43..0.46 rows=1 width=32) (actual time=0.004..0.004 rows=1 loops=121) Index Cond: (id = spso.sku_id) Filter: is_available -> Index Only Scan using shop_feature_ram_sku_pkey on shop_feature_ram_sku sfrs (cost=0.43..0.46 rows=1 width=16) (actual time=0.004..0.004 rows=0 loops=121) Index Cond: (sku_id = spso.sku_id) Filter: (feature_value_code = ANY ('{2048,4096}'::integer[])) Rows Removed by Filter: 1 Heap Fetches: 0 -> Index Scan using shop_product_pkey on shop_product sp (cost=0.42..0.45 rows=1 width=39) (actual time=0.005..0.005 rows=1 loops=30) Index Cond: (id = sps.product_id) Planning time: 12.581 ms Execution time: 6.204 ms
SELECT COUNT(*) FROM shop_product_sku; count --------- 3204349
Составные индексы есть, но они в этом запросе не участвуют, и созданы они не для запросов, а для констрейнтов.
Надеюсь, этого не случится. 95% продавцов прома - это продажи по дропшиппингу, кормление завтраками, перезвоны с прениприятнейшими известиями что внезапно на складе выключили свет.
Сейчас на розетке нету режима, когда на один товар идет offer от двух или более компаний, т.е. тот кто первый пришел с товаром, тот его и продает. Да и выйти на розетку ничего не мешает: заключаешь договор и продаешь. Я б точно не стал сливать эти площадки вместе. Вот что бесит на розетке, так это когда заказываешь 5 позиций, все 5 позиций едут от разных селлеров и ты оплачиваешь 5 доставок. Только по этой причине, уже раз 5 подряд заказывал из других магазинов: comfy, 27.ua, и т.д., при том что у них точки самовывоза прямо под носом, можно удобно проверить товар, оплатить, и забрать. И доставка бесплатная.
Ребятки, ну какой elasticsearch под 2 тысячи товаров, вы в своем уме? Давайте ещё кластер кассандры поднимем.
Что-то вы ляпнули, сами не зная что. При чем тут race conditions? О чем вообще вы говорите?
При правильном дизайне, составные индексы не нужны. Они даже на FLAT таблицах уже не нужны, не говоря о 5/6NF.
Вам нужно пересмотреть дизайн базы: на 2к товарах выборки должны быть очень быстрые, если дизайн правильный составить. У меня на 3 млн. товаров фильтры до 40 мс. занимают.
Это было бы логично, если бы мы мерили скорость выполнения не участка кода, а время от запроса, до получения результата. В чем логичность?
Никто так бенчмарки не делает, особенно на таком коде, который работает за миллисекунды. Тем более, вы не сказали какая версия PHP (в репозиториях 16.04 и 18.04 могут быть разные). CLI без opcache по дефолту работает.
Залетало у вас из-за
query-cache-size = 16Mquery-cache-limit = 512K
которое на MySQL 8.0.3 уже не прокатит. да и в целом, конфиг такой себе.
обычно query_cache включают, и если на реальном workload он помогает, тогда его оставляют. но помогать он может только при убогом дизайне приложения. когда у вас есть запись, query_cache сбрасывается, а т.к. его фронтенд работает в 1 поток, то легко наткнуться на блокировку мьютексов. Другими словами, если у вас на 1000 чтений 1 запись - вам это поможет. Если у вас 1 запись на 50-100 чтений - может только усугубить.
И да, у вас сейчас конфиг заточен скорее под myisam. Если у вас innodb - можно по лучше потюнить.
он и так использует PK для подсчета, проблема в том, что у него WHERE, а без table scan на низком кардиналити у индекса будет перформанс ещё хуже, вот прямо сходил в доку и взял оттуда:
Этот запрос вряд ли отвечает за сам список постов, скорее за пагинатор, который определяет лимиты для последней страницы. Его только кешировать можно. Можно ещё повесить колонку с рандомным uuid, и на неё индекс, где WHERE условия будут совпадать. И потом по ней делать COUNT, но это костыль и так делать не надо. Лучше кешировать, да хоть в файл, и то будет быстрее 6 секунд, не говоря уже о memcached/redis.