danforth

danforth
Рейтинг
153
Регистрация
18.12.2015
LazyBadger:
Что рекомые рейсы могут наступить (и кэширование результатов будет нужно)… для этого только надо, чтобы поднятие "кэша" из базы было быстрее исполнения (сильно кучерявого) запроса на повторную выборку. Я такого представить не могу, ни на 2000 базе, ни на 2000000, но мне положено планировать в предположении "все случается".
Ферштейн?

но кеш импакт не влияет на рейс если он не рекомый. а тогда как вы объясните кучерявость запроса? каждый рейс нужно кешировать чтобы он стал рекомый, иначе будет старвейшн, но смотрите чтоб не начался кеш компакшн. иначе без второй забивки, точно будет не разобрать. или как вариант побрить запрос, чтобы он стал лысый. аэродинамика лысой головы лучше. но это крайняя мера. это если скучно заживется.

LazyBadger, вы сначала ответьте на

LazyBadger:
Так - тоже не делается, кроме отдельных race conditions. Это знает любой профессиональный DBA

При всем уважении, я знаю что такое 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

Составные индексы есть, но они в этом запросе не участвуют, и созданы они не для запросов, а для констрейнтов.

Gray:
Зачем? У Розетки действительно уже много чего продаётся в режиме маркетплейса. Надо только всем продавцам Prom.ua дать выход на Розетку .

Надеюсь, этого не случится. 95% продавцов прома - это продажи по дропшиппингу, кормление завтраками, перезвоны с прениприятнейшими известиями что внезапно на складе выключили свет.

Сейчас на розетке нету режима, когда на один товар идет offer от двух или более компаний, т.е. тот кто первый пришел с товаром, тот его и продает. Да и выйти на розетку ничего не мешает: заключаешь договор и продаешь. Я б точно не стал сливать эти площадки вместе. Вот что бесит на розетке, так это когда заказываешь 5 позиций, все 5 позиций едут от разных селлеров и ты оплачиваешь 5 доставок. Только по этой причине, уже раз 5 подряд заказывал из других магазинов: comfy, 27.ua, и т.д., при том что у них точки самовывоза прямо под носом, можно удобно проверить товар, оплатить, и забрать. И доставка бесплатная.

borisd:
а использовал бы elasticsearch

Ребятки, ну какой elasticsearch под 2 тысячи товаров, вы в своем уме? Давайте ещё кластер кассандры поднимем.

LazyBadger:
Так - тоже не делается, кроме отдельных race conditions.

Что-то вы ляпнули, сами не зная что. При чем тут race conditions? О чем вообще вы говорите?

LazyBadger:
иметь составные индексы на все сочетания (от вырожденнного "1 поле" до "все" ) полей, используемых в WHERE, чтобы запрос в реальном времени был незаметен на фоне других задержек

При правильном дизайне, составные индексы не нужны. Они даже на FLAT таблицах уже не нужны, не говоря о 5/6NF.

Вам нужно пересмотреть дизайн базы: на 2к товарах выборки должны быть очень быстрые, если дизайн правильный составить. У меня на 3 млн. товаров фильтры до 40 мс. занимают.

foxi:
ну это логично что cli из консоли будет быстрее апача. так и должно быть.

Это было бы логично, если бы мы мерили скорость выполнения не участка кода, а время от запроса, до получения результата. В чем логичность?

Никто так бенчмарки не делает, особенно на таком коде, который работает за миллисекунды. Тем более, вы не сказали какая версия PHP (в репозиториях 16.04 и 18.04 могут быть разные). CLI без opcache по дефолту работает.

Залетало у вас из-за

query-cache-size = 16M
query-cache-limit = 512K

которое на MySQL 8.0.3 уже не прокатит. да и в целом, конфиг такой себе.

обычно query_cache включают, и если на реальном workload он помогает, тогда его оставляют. но помогать он может только при убогом дизайне приложения. когда у вас есть запись, query_cache сбрасывается, а т.к. его фронтенд работает в 1 поток, то легко наткнуться на блокировку мьютексов. Другими словами, если у вас на 1000 чтений 1 запись - вам это поможет. Если у вас 1 запись на 50-100 чтений - может только усугубить.

И да, у вас сейчас конфиг заточен скорее под myisam. Если у вас innodb - можно по лучше потюнить.

он и так использует PK для подсчета, проблема в том, что у него WHERE, а без table scan на низком кардиналити у индекса будет перформанс ещё хуже, вот прямо сходил в доку и взял оттуда:

You are using a key with low cardinality (many rows match the key value) through another column. In this case, MySQL assumes that by using the key it probably will do many key lookups and that a table scan would be faster.

Этот запрос вряд ли отвечает за сам список постов, скорее за пагинатор, который определяет лимиты для последней страницы. Его только кешировать можно. Можно ещё повесить колонку с рандомным uuid, и на неё индекс, где WHERE условия будут совпадать. И потом по ней делать COUNT, но это костыль и так делать не надо. Лучше кешировать, да хоть в файл, и то будет быстрее 6 секунд, не говоря уже о memcached/redis.

Всего: 1540