17 июля 2015 г., 11:25

Выборка из (modTemplateVarResource): существенное ускорение при явном указании индекса

Возьмём простой запрос на выборку идентификаторов ресурсов из таблицы (modTemplateVarResource):
SELECT DISTINCT modTemplateVarResource.contentid AS id FROM `modx_site_tmplvar_contentvalues` AS `modTemplateVarResource` WHERE (modTemplateVarResource.tmplvarid = 195) AND (modTemplateVarResource.value IN ('11326','19495','12813','20181','12693','12993','11327'))
Запрос выполняется 0.0151 сек План запроса: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE modTemplateVarResource ref tmplvarid,tv_cnt tv_cnt 4 const 6156 Using where
Далее добавляем в таблицу (modTemplateVarResource) 4 отсутствующих индекса:
ALTER TABLE `modx_site_tmplvar_contentvalues` ADD INDEX `idx_value` ( `value` ( 20 ) ) ALTER TABLE `modx_site_tmplvar_contentvalues` ADD INDEX `idx_tv_value` ( `tmplvarid` , `value` ( 20 ) ) ALTER TABLE `modx_site_tmplvar_contentvalues` ADD INDEX `idx_value_tv` ( `value` ( 20 ), `tmplvarid` ) ALTER TABLE `modx_site_tmplvar_contentvalues` ADD INDEX `idx_content_tv` ( `content`, `tmplvarid` )
Индекс (tv — content) изначально уже имеется (tv_cnt)
Снова запускаем тот же запрос: 0.0038 сек План запроса (используется индекс idx_value_tv): id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE modTemplateVarResource range tmplvarid,tv_cnt,idx_tv_value,idx_value_tv idx_value_tv 66 NULL 60 Using where; Using temporary
Далее непосредственно указываем серверу использовать индекс idx_value_tv:
SELECT DISTINCT modTemplateVarResource.contentid AS id FROM `modx_site_tmplvar_contentvalues` AS `modTemplateVarResource` USE INDEX (idx_value_tv) WHERE (modTemplateVarResource.tmplvarid = 195) AND (modTemplateVarResource.value IN ('11326','19495','12813','20181','12693','12993','11327'))
Получаем: 0.0027 сек. При этом план запроса тот же самый: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE modTemplateVarResource range idx_value_tv idx_value_tv 66 NULL 60 Using where; Using temporary
=============== Почему, в таблице (modTemplateVarResource) изначально нет нужных индексов, задавать не буду — судя по всему, при работе в modx исключительно на уровне xpdo-объектов другие индексы (кроме тех, что имеются «в коробке»), и не нужны.
Вопрос такой: почему при явном указании того же самого индекса запрос работает существенно быстрее. Не чуть быстрее, а существенно быстрее. А ведь запросов при загрузке веб-страницы выполняется куча. И все они могли бы работать гораздо быстрее…
P.S. Если выборку выполнять из таблицы ресурсов, а tv подключать через JOIN и фильтровать так, как приведено здесь (запросы составляются на уровне xpdo, но чистый SQL получается таким как в сабже), то получаем полностью идентичные планы запросов (в части сабжевой фильтрации) и полностью идентичные наблюдения со скоростью их выполнения. На реальных запросах скорость выполнения ощутима.
Почему, в таблице (modTemplateVarResource) изначально нет нужных индексов, задавать не буду — судя по всему, при работе в modx исключительно на уровне xpdo-объектов другие индексы (кроме тех, что имеются «в коробке»), и не нужны.
На счет возможной ненужности — в корне не правильное предположение. Все гораздо проще — это элементарный недосмотр. Повторяюсь: xPDO — это не база данных и даже не тонкий клиент, это просто средство формирования запросов со своими надстройками. Никакие собственные индексы он не умеет строить, использовать и т.п. Это все на совести базы данных.
А индексы правильные не настроены — это не единственная проблема. Элементарно — в разных таблицах в связанных полях не совпадают типы данных. К примеру в одной таблице id int(10)unsigned, а в другой таблице связанная колонка int(11) (не unsigned).
В этом плане в MODX действительно недосмотр большой. К слову, сборка ShopModxBox поставляется сразу с настроенными индексами ;)
И еще большая такая проблема в xPDO — отсутствует поддержка innoDB и транзакций. Сам Джейсон Ковард выражает свое неуважение к этим механизмам, типа они переоценены и не нужны. При этом в xPDO в этом плане большая проблема есть — двойное сохранение связанных объектов, и в случае использования вторичных ключей и транзакций, мы просто получим кучу сообщений об ошибках и сломанную логику. Но мы с Сергеем Прохоровым имеем в этом направлении серьезные наработки и исследования, так что с большой долей вероятности скоро отправим PR, который решает эти проблемы и позволит использовать транзакции. В больших проектах без транзакций просто никак. Когда у вас за раз сохраняется пара десятков связанных объектов, вы замахаетесь отлавливать ошибки и корректные откаты формировать без транзакций.
Если подусловие modTemplateVarResource.tmplvarid = 195 усложнить: modTemplateVarResource.tmplvarid IN (195,196) то MySQL по умолчанию выбирает уже другой индекс — idx_value. При этом явное указание этого же индекса ускоряет запрос в 3 раза.
В обоих случаях — tmplvarid = 195 и tmplvarid IN (195,196) индекс idx_value является самым быстрым
Все гораздо проще — это элементарный недосмотр. Повторяюсь: xPDO — это не база данных и даже не тонкий клиент, это просто средство формирования запросов со своими надстройками.
Я имел ввиду не xpdo-объекты, а объекты modx. Т.е. при работе с объектами modx из составных индексов нужен только tv_cnt (tmplvarid — contentid). При выборке значений TV там сначала создаётся объект TV, затем для него отбираются значения для нужных ресурсов — здесь как раз и используется индекс tv_cnt (tmplvarid — contentid).
К слову, сборка ShopModxBox поставляется сразу с настроенными индексами ;)
В других таблицах (кроме modTemplateVarResource) тоже нужные индексы отсутствуют?
И вот этот вопрос остаётся в силе: Вопрос такой: почему при явном указании того же самого индекса запрос работает существенно быстрее. Не чуть быстрее, а существенно быстрее. А ведь запросов при загрузке веб-страницы выполняется куча. И все они могли бы работать гораздо быстрее…
Это все равно никакого отношения к xPDO не имеет :)
Я имел ввиду не xpdo-объекты, а объекты modx. Т.е. при работе с объектами modx из составных индексов нужен только tv_cnt (tmplvarid — contentid). При выборке значений TV там сначала создаётся объект TV, затем для него отбираются значения для нужных ресурсов — здесь как раз и используется индекс tv_cnt (tmplvarid — contentid).
Мы как на разных языках говорим… Не говорите о MODX в вопросах работы с БД. Если мы разбираем базу данных и работу с ней, MODX-а вообще не следует касаться.
Вопрос такой: почему при явном указании того же самого индекса запрос работает существенно быстрее. Не чуть быстрее, а существенно быстрее. А ведь запросов при загрузке веб-страницы выполняется куча. И все они могли бы работать гораздо быстрее…
Вы внимательней на свой запрос посмотрите, на этот:
SELECT DISTINCT modTemplateVarResource.contentid AS id FROM `modx_site_tmplvar_contentvalues` AS `modTemplateVarResource` WHERE (modTemplateVarResource.tmplvarid = 195) AND (modTemplateVarResource.value IN ('11326','19495','12813','20181','12693','12993','11327'))
У вас выборка не по колонкам tmplvarid и contentid, а по tmplvarid и value. Для колонки value изначально нет индекса в MODX, потому и запрос с условием на эту колонку тормозит. Когда вы создали индекс `idx_value_tv` ( `value` ( 20 ), `tmplvarid` ) и использовали его в запросе, логично, что запрос полетел лучше. Даже если не используется индекс на колонку tmplvarid, запрос по числовым полям в любом случае идет лучше, чем по текстовым, тем более с плавающей длиной.
В других таблицах (кроме modTemplateVarResource) тоже нужные индексы отсутствуют?
Да, есть места. Была когда-то статья, в которой я подробно расписывал в каких колонках чего не хватает, но это было очень давно и сейчас этой статьи в паблике нет. Но планирую ее восстановить.
К слову, сборка ShopModxBox поставляется сразу с настроенными индексами ;)
Вот тут я немного слукавил:) На своих конечных сайтах, где нагрузка повыше, я создаю эти индексы. А вот в сборку не получается их запилить, так как мы не включаем в нее само ядро MODX-а. То есть при установке MODX-а создаются его родные индексы, и наши дополнительные в него не могут быть включены. Подумаю на счет того, чтобы все-таки подготовить и отправить PR в ядро с поправленной структурой и индексами.
Здравствуйте, Николай! Вы как-то писали о том, что планируете написать статью о создании крупного высокопосещаемого новостного портала на МОДХ Рево. Мы все ждём. :) Я по крайней мере точно жду. :)
Да, и у меня это в расписании есть. Но что-то дела основные загрузили, так что приходится сдвигать это. Видите же, вообще практически ничего не пишу :) Как только освобожусь (а это скорее всего только в начале августа), так сразу напишу.
Николай, не могли бы вы прокомментировать вот этот профайлинг. Запрос — как в сабже (условия по тем же полям — TV и значение), но сами условия немного сложнее (результат выборки — 150 записей).
starting 0.000011 checking query cache for query 0.000101 Opening tables 0.000010 System lock 0.000004 Table lock 0.000027 init 0.000037 optimizing 0.000020 statistics 0.018192 preparing 0.000032 Creating tmp table 0.000029 executing 0.000002 Copying to tmp table 0.011076 Sending data 0.000065 end 0.000002 removing tmp table 0.000006 end 0.000003 query end 0.000003 freeing items 0.000210 storing result in query cache 0.000008 logging slow query 0.000002 cleaning up 0.000003
Практически всё время съедают statistics и Copying to tmp table. Большой statistics, возможно, из-за низких значений некоторых настроек MySQL, связанных с памятью (не совсем понимаю фразу the server is probably disk-bound performing other work из справки) А Copying to tmp table — не понятно, на диск или в оперативку…
P.S. Именно сабжевый запрос даёт аналогичный профайлинг, но Copying to tmp table в процентном соотношении занимает не так много времени, но statistics по-прежнему высокий.
Большой statistics, возможно, из-за низких значений некоторых настроек MySQL, связанных с памятью (не совсем понимаю фразу the server is probably disk-bound performing other work из справки)
А может быть, причина в ограничении скорости операций чтения на VPS?
Мегаподробно не расскажу. Сам не все знаю. Но идеи есть. Дело в том, что прежде чем получить данные из связанных таблиц, эти данные должны набиться во временную таблицу. Это нормально и логично. Statistics в данном случае — это сбор результирующих данных (то есть сколько всего строк получится, какие соответствуют условиям и т.п.). Нет ведь смысла во временную таблицу копировать вообще все. Нужно только то, что соответствует логике. Собственно, вот тут и важны индексы, так как если индексов не будет, то СУБД придется читать полностью файлы указанных таблиц, чтобы собрать всю статистику. Это и есть самая затратная часть в запросах из более чем одной таблицы. А когда результирующие данные в наличии и во временной таблице, тогда окончательную выборку сделать на составляет труда и не занимает времени.
Дело в том, что прежде чем получить данные из связанных таблиц, эти данные должны набиться во временную таблицу.
Тогда целесообразно обеспечить набивку этих данных гарантированно в оперативку. На вскидку не назовёте соответствующую настройку (настройки) MySQL?
А вы что, думаете они в файл набиваются? Сказано «создается временная таблица», но разве сказано, что она именно в файле создается. Есть движок таблиц Memory в MySQL, который как раз и создает таблицу в оперативке. Разве можно в данном случае сказать, что таблица не создается?
При выполнении сабжевых запросов MySQL сам выбирает подходящий индекс. Но если тому же самому запросу для той же самой таблицы указать тот же самый индекс (USE INDEX), то запрос начинает выполняться в 1,5-3 раза быстрее.
Сейчас столкнулся с простым запросом (используется JOIN собственной таблицы), который после явного указания того же самого индекса начинает выполняться в 17 раз быстрее (с 0.0650 до 0.0037 сек). Я в ужасе.
Получается, что MySQL ОЧЕНЬ много времени тратит на выбор нужного индекса?
Получается, что он не всегда может выбрать правильный индекс :) Он же не использует все их вместе сразу. Иногда он правильно угадывает индекс, а иногда нет.
И, не за бывайте про кеширование результатов запросов на уровне самого мускула. А то выполните один запрос, потом его же, но с указанием другого индекса, а он результат уже из кеша берет… И делайте запросы на больших объемах данных, хотя бы на нескольких десятках тысяч записей, и лучше в цикле итераций так на тысячу.
Так я же говорю, что индекс он сам выбирает и выбирает правильно. Но если я тот же самый индекс указываю явно, запрос выполняется в разы быстрее (в последнем запросе — в 17 раз быстрее).
Я перед каждым запуском запроса вношу реальное изменение в ту таблицу, которая в запросе используется (как правило, это таблица ресурсов). Для этого у меня рядом отдельная вкладка с формой редактирования тестового ресурса.
На счет правильности подробнее свои мысли можете выложить? Я вот думаю так: у вас вот в профилировании информация
range tmplvarid,tv_cnt,idx_tv_value,idx_value_tv
Это возможные используемые индексы. Вот как у меня в запросе: ? Тут два возможных индекса: contentid,value. А вот запрос, где я явно указал какой индекс использовать: ? А здесь только один возможный индекс, который я и указал. Не кажется ли вам логичным, что когда индекс явно указан, мускулу не приходится перебирать все остальные индексы, чтобы выяснить какой из них наиболее подходящий? И что это должно положительно сказываться на скорость выполнения запроса (и скорее всего на statistics)?
Никогда бы не подумал, что MySQL тратит так много времени на выбор подходящего индекса из нескольких возможных. Это время сравнимо со временем выполнения запроса. А если в таблице индексов много (и многие из них возможно использовать в запросе), то выбор оптимального занимает времени на порядок больше, чем время выполнения запроса.
Так вы покопайте глубже и разузнайте каким образом мускул выбирает нужный индекс. С большой долей вероятности он какую-то выборку данных для этого делает чтобы понять какой индекс лучше подходит. На хабре когда-то статья была, в которой чел писал, что мускул не всегда выбирает наиболее правильный индекс. Это может означать только то, что механизм выбора довольно сложный и не однозначный.
При наличии конструкции
... IN (конкретные значения)
MySQL начинает долго выбирать индексы
Вот 3 примера: Добавляем в таблицу (modx_site_tmplvar_contentvalues) 4 индекса:
ALTER TABLE `modx_site_tmplvar_contentvalues` ADD INDEX `idx_value` ( `value` ( 20 ) ) ALTER TABLE `modx_site_tmplvar_contentvalues` ADD INDEX `idx_tv_value` ( `tmplvarid` , `value` ( 20 ) ) ALTER TABLE `modx_site_tmplvar_contentvalues` ADD INDEX `idx_value_tv` ( `value` ( 20 ), `tmplvarid` ) ALTER TABLE `modx_site_tmplvar_contentvalues` ADD INDEX `idx_content_tv` ( `content`, `tmplvarid` )
Пример 1
SELECT DISTINCT `modx_site_tmplvar_contentvalues`.contentid AS id FROM `modx_site_tmplvar_contentvalues` WHERE ((`modx_site_tmplvar_contentvalues`.tmplvarid IN (208,209)) AND ((modx_site_tmplvar_contentvalues.value = '18') OR (modx_site_tmplvar_contentvalues.value = '11') OR (modx_site_tmplvar_contentvalues.value = '29') OR (modx_site_tmplvar_contentvalues.value = '60') OR (modx_site_tmplvar_contentvalues.value = '10') OR (modx_site_tmplvar_contentvalues.value = '20') OR (modx_site_tmplvar_contentvalues.value = '23') OR (modx_site_tmplvar_contentvalues.value = '22') OR (modx_site_tmplvar_contentvalues.value = '21') OR (modx_site_tmplvar_contentvalues.value = '12') OR (modx_site_tmplvar_contentvalues.value = '13') OR (modx_site_tmplvar_contentvalues.value = '4') OR (modx_site_tmplvar_contentvalues.value = '26') OR (modx_site_tmplvar_contentvalues.value = '1а') OR (modx_site_tmplvar_contentvalues.value = '16(а)') OR (modx_site_tmplvar_contentvalues.value = '14') OR (modx_site_tmplvar_contentvalues.value = '79')))
Замечание: можно условие записать и через IN — на скорость и описываемое поведение запроса это никак не повлияет.
При явном указании индекса [idx_value_tv] (это самый быстрый индекс) запрос выполняется 0.0105 сек. Если никакой индекс явно не указывать, то запрос выполняется 0.0161 сек. Здесь MySQL самостоятельно выбирает индекс [idx_value_tv] 0.0056 сек.
Пример 2
SELECT DISTINCT `modx_site_tmplvar_contentvalues`.contentid AS id FROM `modx_site_tmplvar_contentvalues` WHERE ((`modx_site_tmplvar_contentvalues`.tmplvarid IN (195, 207)) AND (`modx_site_tmplvar_contentvalues`.value IN ('13369','13605','18477','17217','15807','12812','13615','19166','12440','12993','13733','15011','13362','12693','13357','19499','13606')))
При явном указании индекса [idx_value] (это самый быстрый индекс для данного запроса) запрос выполняется 0.0059 сек. Если никакой индекс явно не указывать, то запрос выполняется 0.0182 сек. Здесь MySQL самостоятельно выбирает индекс [idx_value] 0.0123 сек.
Пример 3 (с использованием таблицы ресурсов)
SELECT modResource.id AS bigId, modResource.properties AS properties FROM `modx_site_content` AS `modResource` LEFT JOIN `modx_site_tmplvar_contentvalues` `RRR` ON ( RRR.contentid = modResource.id AND RRR.tmplvarid = 30 ) WHERE ( ( `modResource`.`template` = 25 OR `RRR`.`value` = '12' ) AND `modResource`.`class_key` = 'modDocument' AND `modResource`.`deleted` = 0 AND `modResource`.`published` = 1 AND `modResource`.`id` IN (2223,2230,2234,2244,2250,2256,2258,2259,2261,2266,2267,2277,2299,2300,2314,2315,2316,2322,2346,2347,2348,2349,2350,2354,2355,2356,2357,2358,2365,2368,2373,2379,2384,2385,2386,2387,2391,2394,2401,2415,2425,2427,2436,2441,2442,2444,2445,2451,2455,2472,2483,2487,2506,2568,2571,2572,2577,2580,2581,2584,2591,2593,2606,2607,2619,2626,2628,2632,2637,2647,2674,2675,2676,2677,2678,2682,2686,2699,2704,2706,2712,2734,2764,2784,2796,2797,2800,2806,2807,2808,2809,2817,2819,2823,2832,2839,2849,2850,2860,2929,2931,2934,2940,3243,3248,3351,3352,3359,3365,3367,3392,3398,3399,3403,3405,3413,3419,3420,3424,3435,3441,3447,3452,3453,3454,3460,3469,3470,3477,3478,3482,3489,3502,3506,3511,3512,3515,3527,3536,3543,3552,3562,3566,3573,3575,3586,3596,3604,3606,3609,3615,3656,3666,3675,3677,3678,3681,3687,3691,3695,3707,3708,3711,3720,3725,3729,3733,3734,3742,3758,3767,3774,3775,3782,3783,3784,3785,3787,3790,3792,3793,3795,3799,3802,3803,3805,3807,3808,3818,3822,3831,3833,3839,3852,3859,3881,3892,3899,3906,3907,3912,3916,3917,3927,3929,3934,3936,3938,3947,3954,3958,3961,3962,3966,3967,3970,3971,3974,3984,3987,3990,4006,4008,4009,4018,4019,4021,4025,4030,4031,4044,4045,4069,4073,4078,4088,4095,4103,4104,4106,4107,4133,4134,4137,4138,4141,4145,4169,4173,4174,4194,4216,4241,4242,4243,4835,5598,5599,5621,5622,5623,5626,5627,5628,5629,5653,5681,5682,6613,6615,7487,7625,7627,7628,7629,7659,7660,7671,7679,7777,7782,7785,7786,7792,7793,7814,7841,11106,11186,11202,21078,21096,21097,21100,21101,21102,21104,21105,21113,21163,21165,21166,21170,21172,21173,21174,21175,21178,21180,21182,21190,21191,21193,21201,21215,21222,21226,21232,21256,21257,21261,21262,21263,21264,21265,21266,21267,21268,21269,21280,21323,21324,21325,21332,21337,21338,21341,21343,21378,21380,21381,21382,21383,21385,21392,21393,21414,21427,21478,21479,21523,21524,21530,21531,21534,21535,21574,21575,21576,21580,21582,21583,21601,21602,21618,21624,21639,21640,21641,21645,21646,21647,21649,21650,21651,21654,21663,21665,21699,21700,21704,21706,21708,21710,21711,21712,21724,21748,21787,21788,21794,21811,21815,21816,21819,21820,21821,21823,21837,21838,21863,21872,21891,21905,21988,21991,22004,22315,22664,22668,22669,22671,22672,22673,22674,22677,22678,22679,22680,22683,22685,22758,22767,22768,22769,22775,22776,22814,22816,22827,22829,22833,22976,22980,22981,22983,22984,22985,22994,23606,23645,23647,23744,23745,23746,23748,23750,23752,23756,23759,23761,23768,23776,24266,24581,24582,24584,24585) )
Этот запрос выполняется 0.0072 сек. При этом MySQL самостоятельно выбирает индекс (PRIMARY). Если этот индекс указать явно, то запрос выполняется за 0.0066. Т.е. из стандартного набора индексов (содержащихся в таблице ресурсов) в этом запросе MySQL выбирает индекс (PRIMARY) всего 0.0006 сек.
Далее в таблицу ресурсов добавляем индекс Добавляем в таблицу ресурсов индекс:
ALTER TABLE `modx_site_content` ADD INDEX `idx_id_class_published_deleted` ( `id`, `class_key`, `published`, `deleted` ))
Снова выполняем запрос — 0.0345 сек. При этом MySQL по-прежнему выбирает индекс (PRIMARY), но выбирает уже 0.0273 сек.
Далее в таблицу ресурсов добавляем 2-й индекс:
ALTER TABLE `modx_site_content` ADD INDEX `idx_class_published_deleted_id` (`class_key`, `published`, `deleted`, `id`))
Выполняем запрос — 0.23 сек. При этом MySQL по-прежнему выбирает индекс (PRIMARY), но выбирает аж 0.22 сек. Ужасный результат.
Замечание. Если в 3-м примере явно указать один из добавленных индексов, то запрос выполняется существенно медленнее, чем изначально, когда MySQL самостоятельно выбирает индекс (PRIMARY). Т.е. эти индексы для данного запроса неподходящие (почему — не совсем понятно). — Таким образом, удалил все собственные индексы из таблицы ресурсов. От греха подальше. Что делать с собственными индексами в таблице (modx_site_tmplvar_contentvalues) — вопрос открытый. Опасная эта вещь — добавлять индексы.
Хорошо. В новой версии getdata-процессоров изучу возможность в xPDO указывать собственные индексы. Но насколько я могу судить при беглом осмотре, этого нет там. Будем думать.
А в xpdo вроде как указание индексов вообще не предусмотрено. Если только собственную обёртку писать над xpdo…
Да и вообще, это не решение проблемы. Поскольку большинство пользователей не будет указывать явно индексы (на то они и пользователи). В этом случае при наличии дополнительных индексов в таблицах (как вы говорите, в ваших пакетах они присутствуют) некоторые запросы станут сильно тормозить.
Впрочем, если использовать процессоры, то никто не мешает перед выполнением запроса регуляркой вставить USE INDEX куда нужно. У себя я так и сделал на проблемных запросах.
Да, xPDO такого нет. Но я буду смотреть вариант запулить пуллреквест Джейсону. Если примет, то механизм будет.
С большой долей вероятности он какую-то выборку данных для этого делает чтобы понять какой индекс лучше подходит
Скорее всего, эту самую выборку (необходимую для выбора индекса) MySQL выполняет столько раз, сколько значений содержится в конструкции IN. Такой вывод напрашивается из приведённых примеров.
Если это действительно так, то выбор индекса будет осуществляться тем дольше: а) чем больше в таблице индексов (вероятно, роль играют не все индексы, а с определённой структурой, зависящей от конструкции запроса) б) чем больше значений в конструкции IN в) чем больше записей в таблицах, участвующих в запросе
Ну а конкретнее — это уже лезть в исходники…
Логично, что чем больше данных в конструкции IN, тем сложнее запрос. Но вряд ли для каждого значения он проверяет все индексы. В любом случае, мы уже выяснили, что указывать конкретный индекс — это правильно и производительность выше. Будем посмотреть как время появится. Сейчас просто совсем некогда.

Добавить комментарий