Перейти к содержимому

Как ускорить выборку данных mysql

  • автор:

Как изменить сам запрос или DDL, чтобы ускорить выборку по диапазону дат?

куда каждый месяц (поле period хранит дату = 1 число этого месяца) записываются несколько десятков тысяч записей. Сейчас в ней данные за 62 месяца, 2016426 записей. Один из запросов должен подсчитывать сумму h_sum + hw_sum за несколько месяцев (помесячно). Если так:

SELECT period, SUM(h_sum+hw_sum) paid FROM data WHERE period BETWEEN '2023-01-01' AND '2023-07-01' GROUP BY period ORDER BY period; 

запрос выполняется 19 сек! Его EXPLAIN:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE data \N index period period 4 \N 1934197 33,18 Using where

Если переписать его с использованием оконных функций:

SELECT DISTINCT period, SUM(h_sum+hw_sum) OVER (PARTITION BY period ORDER BY period) paid FROM data WHERE period BETWEEN '2023-01-01' AND '2023-07-01' 

то время выполнения уменьшается до 8 сек, но перестает использоваться индекс, EXPLAIN:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE data \N ALL period \N \N \N 1934197 33,18 Using where; Using filesort

Если принудить использовать индекс:

SELECT DISTINCT period, SUM(h_sum+hw_sum) OVER (PARTITION BY period ORDER BY period) paid FROM data FORCE INDEX (period) WHERE period BETWEEN '2023-01-01' AND '2023-07-01' 

то время уменьшается до 4 сек, но EXPLAIN (поле extra) становится совсем плохим:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE data \N range period period 4 \N 641720 100,00 Using index condition; Using MRR; Using filesort

Вопрос: можно ли еще как-то оптимизировать/изменить запрос для ускорения времени выполнения (чем больше месяцев в выборке, тем дольше считается)? Может изменить тип поля? На что? Индекс? Структуру таблицы? Еще что-то? Доп. вопрос: так ли нужен ORDER BY period , если данные записываются всегда последовательно по месяцам (т.е., к примеру, данные января 2023 не могут быть записаны ранее декабря 2022)? Если убрать его из запросов, то ничего не меняется: ни порядок месяцев в выборке, ни скорость выполнения.

Отслеживать
задан 11 июл 2023 в 6:49
35 3 3 бронзовых знака

но EXPLAIN (поле extra) становится совсем плохим Тебя интересует скорость работы или красота плана? можно ли еще как-то оптимизировать Да элементарно, Ватсон. Заводишь ещё одну таблицу, куда по завершении месяца считаешь и записываешь суммы за этот месяц. И когда нужна статистика, не полощешь всю таблицу, а берёшь предрасчётные данные. Если иногда нужна и статистика за неполный текущий месяц — значит, пересчитываешь сумму после каждого пополнения, ежедневно. так ли нужен ORDER BY period Да, без него сервер имеет право в любой момент изменить порядок возврата записей. И не предупредит..

11 июл 2023 в 12:17
@Akina спасибо, очень не хватало твоих советов после кончины sql.ru )
12 июл 2023 в 5:34

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Селективность обычного индекса period

Индекс в запросе не особенно помогает, так как 641720 строк — это треть всех данных таблицы (EXPLAIN: 641720/2016426 ~ 1/3. Или колонка filtered 33,18 — там где с индексом). То есть селективность 1/3 — маленькая.

Для получения значений h_sum и hw_sum все равно берутся данные собственно из файла данных, а не из файла индекса — то есть происходит дополнительное чтение с диска.

  1. прочитать малоселективный индекс, а затем по ссылкам из него дополнительно прочитать h_sum + hw_sum из файла данных
  1. прочитать только файл данных, по ходу фильтруя данные

И выбирает второй вариант. И не особенно ошибается со своим выбором — разница всего 19/8 ~ 2 раза. Обычно индексы работают многократно быстрее.

Как можно улучшить? Сделать покрывающий индекс или делать предварительные расчеты. Поправить тип period.

Покрывающий индекс

Можете сделать один индекс сразу по нескольким полям: period , h_sum , hw_sum — он станет покрывающим в данном конкретном запросе. Порядок полей важен. Тогда будет использоваться исключительно индекс.

Мне трудно сказать, насколько это увеличит скорость, так как все равно много данных. А должно стать быстрее банально из-за того, что индекс компактнее чем все данные.

Получение данных из покрывающего индекса. Допустим 2016426 записей. Размер одной записи: date + 2 * double + PK . Я не стал искать точные размеры, думаю в 100 байт укладывается. Получилось 192 Мб. Чтение с диска займет доли секунды.

Также БД придется сделать суммирование 641720 * 2 = 1283440 раз. Если одна операция сложения double это 1-3 такта, то на 2 ГГц процессоре потратится 1283440÷2000000000 = 0,0006 сек. CPU делает и другие операции типа записи в кеш L1, я их не стал тут учитывать. Если я правильно рассчитываю, этим временем вообще можно пренебречь.

В итоге покрывающий индекс должен существенно помочь. Но это не точно.

Предварительная агрегация

OLTP — обработка транзакций в реальном времени. Типичный веб-сайт, где важно время отклика. OLAP — аналитика. Она всегда долгая из-за агрегации.

Хотите OLAP в реальном времени? Делайте предварительные расчеты и используйте простой SELECT по результатам.

  • Сделать агрегацию средствами своего языка программирования и хранить в отдельной таблице. Или вообще в Redis кешировать.
  • Настроить триггеры: при любой вставке/обновлении/удалении данных в таблицу data сама БД будет триггериться и обновлять таблицу аналитики типа data_by_period .

NOT NULL

period date DEFAULT NULL — я везде читал, что NOT NULL быстрее. Но разница может быть ничтожная. Пробуйте.

Оптимизация MySql запросов

У большинства MySQL серверов включено кэширование запросов. Один из наилучших способов улучшения производительности — просто предоставить кэширование самой базе данных. Когда какой-либо запрос повторяется много раз, его результат берется из кэша, что гораздо быстрее прямого обращения к базе данных. Основная проблема в том, что многие просто используют запросы, которые не могут быть закэшированы:

// запрос не будет кэширован $r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()"); // а так будет! $today = date("Y-m-d"); $r = mysql_query("SELECT username FROM user WHERE signup_date >= '$today'");

Причина в том, что в первом запросе используется функция CURDATE(). Это относиться ко всем функциям, подобным NOW(), RAND() и другим, результат которых недетерминирован. Если результат функции может измениться, то MySQL не кэширует такой запрос. В данном примере это можно предотвратить вычислением даты до выполнения запроса.

Используйте EXPLAIN для ваших запросов SELECT

Используя EXPLAIN, вы можете посмотреть, как именно MySQL выполняет ваш запрос. Это может помочь вам избавиться от слабых мест производительности и других проблем в вашем запросе или в структуре таблиц.
Результат EXPLAIN покажет вам, какие используются индексы, как выбираются и сортируются таблицы и т.д.
Возьмите ваш SELECT запрос (он может быть сложным, с объединениями) и добавьте в начало ключевое слово EXPLAIN. Для этого вы можете использовать phpmyadmin. В результате вы получите очень интересную таблицу. Для примера, пусть я забыл добавить индекс в таблицу, которая участвует в объединении:

После добавления индекса для поля group_id:

Теперь вместо 7883 строк, выбираются только 9 и 16 строк из двух таблиц. Перемножение всех чисел в столбце rows даст число прямо пропорциональное производительности запроса.

LIMIT 1, когда нужна единственная строка

Иногда, обращаясь к таблице, вы точно знаете, что вам нужна только одна конкретная строка. Например, нужно получить одну уникальную строку или просто проверить существование записей, удовлетворяющих запросу WHERE.
В этом случае, добавление LIMIT 1 в ваш запрос будет оптимальней. Таким образом, база данных остановит выборку записей, после нахождения первой же, вместо того, чтобы выбрать всю таблицу или индекс.

// есть пользователи в Alabama? // можно так: $r = mysql_query("SELECT * FROM user WHERE state = 'Alabama'"); if (mysql_num_rows($r) > 0) < // . >// но так лучше: $r = mysql_query("SELECT * FROM user WHERE state = 'Alabama' LIMIT 1"); if (mysql_num_rows($r) > 0) < // . >

Индексируйте поля, по которым ищите

Индекс это не только основной или уникальный ключ. Это так же любые столбцы в таблице, которые вы используете для поиска и их можно проиндексировать.

Как вы можете заметить, это правило также применимо для части строк, например — «last_name LIKE ‘a%’». При поиске с начала строки, MySQL использует индекс этого столбца.
Вы так же должны понимать, что это не сработает для регулярных выражений. Например, когда вы ищите слово (т.е. «WHERE post_content LIKE ‘%apple%’»), то от обычного индекса не будет никакого толку. Лучше будет использовать полнотекстовый поиск или создать вашу собственную систему индексации.

Индексируйте поля для объединения и используйте для них одинаковые типы столбцов

Если ваше приложение содержит много объединений таблиц, вам необходимо проиндексировать в обеих таблицах поля, используемые для объединения. Это повлияет на то, как MySQL делает внутреннюю оптимизацию объединений.
Так же эти столбцы должны быть одного типа. Например, если вы объединяете столбец DECIMAL со столбцом INT из другой таблицы, MySQL не сможет использовать хотя бы один из индексов. Даже кодировки символов должны быть одного типа для строковых столбцов.

// выборки компаний в штате пользователя $r = mysql_query("SELECT company_name FROM users JOIN companies ON (users.state = companies.state) users.id = $user_id"); // обе колонки state должны быть проиндексированы // они обе должны иметь один тип данных и кодировку символов // а иначе MySQL сделает полную выборку из этих таблиц

Не используйте ORDER BY RAND() для больших таблиц

(Имеется в виду выборка единственной строки. Примечание переводчика)

Это одна из тех вещей, который выглядят очень хорошо на первый взгляд, но многие начинающие программисты попались на эту удочку. Вы даже не представляете, какое слабое место в производительности возникнет, если будете использовать это в запросах.
Если вам действительно нужен случайный порядок строк в запросе, то есть лучшие способы сделать это. Конечно, это приведет к дополнительному коду, но позволит избавиться от слабого места в производительности, которое будет сужаться экспоненциально при увеличении данных. Проблема в том, что MySQL будет выполнять RAND() (а это нагрузка на процессор) для каждой строки при сортировке, выдавая только одну строку.

Таким образом вы выберите случайный номер, который меньше количества строк и используете его для смещения в LIMIT.

$n_rand = mt_rand(1, $mysqli->query(«SELECT MAX(id) FROM `table`»));
$result_set = $mysqli->query(«SELECT * FROM `table` WHERE `id`=’$n_rand'»);
?>

SELECT f.id FROM files f JOIN ( SELECT RAND() * (SELECT MAX(id) FROM files) AS max_id ) AS m WHERE f.id >= m.max_id ORDER BY f.id ASC LIMIT 1;

Избегайте SELECT *

Чем больше данных считывается из таблицы, тем медленнее запрос. Это увеличивает время работы с хранилищем данных. Также, когда сервер базы данных установлен отдельно от web-сервера, будет большая задержка при передаче данных по сети.
Прописывайте, какие именно столбцы из запроса вам нужны.

// не очень хорошо: $r = mysql_query(«SELECT * FROM user WHERE user_id = 1»); $d = mysql_fetch_assoc($r); echo «Welcome »; // лучше: $r = mysql_query(«SELECT username FROM user WHERE user_id = 1»); $d = mysql_fetch_assoc($r); echo «Welcome »; // разница более значительна при большем наборе данных.

Старайтесь всегда создать поле ID

В каждой таблице нужно поле id, которое будет PRIMARY KEY, AUTO_INCREMENT, а так же иметь тип INT. Так же неплохо, чтобы оно было UNSIGNED, т.к. вряд ли у идентификатора будут отрицательные значения.
Даже если в вашей таблице пользователей есть уникальное поле username, не делаете его основным ключом. Использование поля VARCHAR, как основного ключа, очень медлительно. Да и структура вашего кода, относящаяся к пользователям, будет гораздо лучше, если у каждого пользователя будет свой внутренний идентификатор.
Есть так же и внутренние операции MySQL, использующие первичный ключ. И это становиться очень важно для более сложных конфигураций базы данных (кластеры, распараллеливание и т.д.)
Исключение из этого правила составляют «таблицы ассоциаций», используемые для связи «многие-ко-многим» между 2 таблицами. Например, таблица «posts_tags», содержит 2 поля: post_id, tag_id, который используется для объединения между двумя таблицами «Posts» и «Tags». Эта таблица будет иметь первичный ключ составленный из 2 полей.

Используйте NOT NULL, если это возможно

Если есть особые причины использовать NULL — используйте его. Но перед этим спросите себя — есть ли разница между пустой строкой и NULL (для INT — 0 или NULL). Если таких причин нет, используйте NOT NULL.
NULL занимает больше места и, к тому же, усложняет сравнения с таким полем. Избегайте его, если это возможно. Тем не менее, бывают веские причины использовать NULL, это не всегда плохо.
Из документации MySQL:
«Столбцы NULL занимают больше места в записи, из-за необходимости отмечать, что это NULL значение. Для таблиц MyISAM, каждое поле с NULL занимает 1 дополнительный бит, который округляется до ближайшего байта».

Подготовленные выражения

Есть несколько фактов преимущества использования подготовленных выражений в области безопасности и производительности.

Подготовленные выражения по умолчанию фильтруют переменные, которые к ним привязаны, что является очень хорошей защитой ваших приложений против атак типа «инъекция SQL». Конечно, вы можете фильтровать переменные вручную тоже, но такие методы более подвержены ошибкам и забывчивости программистов.

Преимущества в области производительности более существенно проявляются в случаях многократного использования одного и того же запроса в приложении. Можно назначать различные значения для одного подготовленного выражения, которое MySQL будет анализировать только один раз.

Кроме того, последние версии MySQL передают подготовленные выражения в бинарной форме, которая более эффективна и помогает сокращать задержки при передаче данных по сети.

Было время, когда программисты избегали использования подготовленных выражений только по причине того, что они не кэшировались MySQL. Но начиная с версии 5.1 кэширование также поддерживается для запросов подготовленных выражений.

Для использования подготовленных выражений в PHP можно использовать расширение mysqli или PDO.

// Создаем подготовленное выражение if ($stmt = $mysqli->prepare("SELECT username FROM user WHERE state=?")) < // Привязываем параметры $stmt->bind_param("s", $state); // Выполняем $stmt->execute(); // Привязываем переменные результата $stmt->bind_result($username); // Получаем значения $stmt->fetch(); printf("%s is from %s\n", $username, $state); $stmt->close(); >

Небуферизованные запросы

Обычно, делая запрос, скрипт останавливается и ждет результата его выполнения. Вы можете изменить это, используя небуферизованные запросы.
Хорошее описание есть в документации функции mysql_unbuffered_query():

«mysql_unbuffered_query() отправляет SQL-запрос в MySQL, не извлекая и не автоматически буферизуя результирующие ряды, как это делает mysql_query(). С одной стороны, это сохраняет значительное количество памяти для SQL-запросов, дающих большие результирующие наборы. С другой стороны, вы можете начать работу с результирующим набором срезу после получения первого ряда: вам не нужно ожидать выполнения полного SQL-запроса»

Однако есть определенные ограничения. Вам придется считывать все записи или вызывать mysql_free_result() прежде, чем вы сможете выполнить другой запрос. Так же вы не можете использовать mysql_num_rows() или mysql_data_seek() для результата функции.

Хранение IP в UNSIGNED INT

Многие программисты хранят IP адреса в поле типа VARCHAR(15), не зная что можно хранить его в целочисленном виде. INT занимает 4 байта и имеет фиксированный размер поля.
Убедитесь, что используете UNSIGNED INT, т.к. IP можно записать как 32 битное беззнаковое число.
Используйте в запросе INET_ATON() для конвертирования IP адреса в число, и INET_NTOA() для обратного преобразования. Такие же, такие функции есть и в PHP — ip2long() и long2ip() (в php эти функции могут вернуть и отрицательные значения. замечание от хабраюзера The_Lion).

$r = "UPDATE users SET ip = INET_ATON('') WHERE user_id = $user_id";

Таблицы фиксированного размера (статичные) — быстрее

Если каждая колонка в таблице имеет фиксированный размер, то такая таблица называется «статичной» или «фиксированного размера». Пример колонок не фиксированной длины: VARCHAR, TEXT, BLOB. Если включить в таблицу такое поле, она перестанет быть фиксированной и будет обрабатываться MySQL по-другому.
Использование таких таблицы увеличит эффективность, т.к. MySQL может просматривать записи в них быстрее. Когда надо выбрать нужную строку таблицы, MySQL может очень быстро вычислить ее позицию. Если размер записи не фиксирован, ее поиск происходит по индексу.
Так же эти таблицы проще кэшировать и восстанавливать после падения базы. Например, если перевести VARCHAR(20) в CHAR(20), запись будет занимать 20 байтов, вне зависимости от ее реального содержания.
Используя метод «вертикального разделения», вы можете вынести столбцы с переменной длиной строки в отдельную таблицу.

Вертикальное разделение

Вертикальное разделение — означает разделение таблицы по столбцам для увеличения производительности.
Пример 1. Если в таблице пользователей хранятся адреса, то не факт что они будут нужны вам очень часто. Вы можете разбить таблицу и хранить адреса в отдельной таблице. Таким образом, таблица пользователей сократиться в размере. Производительность возрастет.
Пример 2. У вас есть поле «last_login» в таблице. Оно обновляется при каждом входе пользователя на сайт. Но все изменения в таблице очищают ее кэш. Храня это поле в другой таблице, вы сведете изменения в таблице пользователей к минимуму.
Но если вы будете постоянно использовать объединение этих таблиц, это приведет к ухудшению производительности.

Разделяйте большие запросы DELETE и INSERT

Если вам необходимо сделать большой запрос на удаление или вставку данных, надо быть осторожным, чтобы не нарушить работу приложения. Выполнение большого запроса может заблокировать таблицу и привести к неправильной работе всего приложения.
Apache может выполнять несколько параллельных процессов одновременно. Поэтому он работает более эффективно, если скрипты выполняются как можно быстрее.
Если вы блокируете таблицы на долгий срок (например, на 30 секунд или дольше), то при большой посещаемости сайта, может возникнуть большая очередь процессов и запросов, что может привести к медленной работе сайта или даже к падению сервера.
Если у вас есть такие запросы, используйте LIMIT, чтобы выполнять их небольшими сериями.

while (1) < mysql_query("DELETE FROM logs WHERE log_date // небольшая пауза usleep(50000); >

Выбирайте правильный тип таблицы

Два основных типа таблиц — MyISAM и InnoDB, у каждого есть свои плюсы и минусы.
MyISAM хорошо считывает из таблиц большое количество данных, но он плох для записи. Даже если вы изменяете всего одну строку, блокируется вся таблица, и ни один процесс не может ничего из нее прочитать. MyISAM очень быстро выполняет запросы типа SELECT COUNT(*).
У InnoDB более сложный механизм хранения данных, и он может быть медленнее, чем MyISAM, для маленьких приложений. Но он поддерживает блокировку строк, что более эффективно при масштабировании. Так же поддерживаются некоторые дополнительные функции, такие операции как транзакции.

На нашем сайте Вы можете найти надежный платный хостинг.

Как ускорить выборку из таблицы с миллионом записей?

Всем привет! Ребят, есть на vps база, в ней табличка q. Так вот в ней около десяти полей varchar и id autoincrement primary key.
Записей более чем миллион, на 500мб. Делаю выборку:
select count(*) from q where flag = 0
Записей много, и выборка идет долго, дольше минуты или около того. Дело в vps, или тут никак не избежать такого тайминга?

UPD:
SELECT * FROM q LIMIT 10
Данный запрос выполняется 10 секунд. В чем может быть дело?

  • Вопрос задан более трёх лет назад
  • 994 просмотра

Как ускорить выборку из mysql?

запрос вида «select id,value from table where limit 1» может выполняться от 3 секунд до 30
как ускорить выполнение запроса хотя бы до десятых долей секунды?
можете вкратце рассказать про индесы? вроде применил к полю id, но результата не вижу
поможет ли разбиение таблицы на несколько, скажем по 10 тысяч?
заранее благодарю за ответы

  • Вопрос задан более трёх лет назад
  • 2537 просмотров

Комментировать
Решения вопроса 2
Full-stack developer (Symfony, Angular)
Есть мнение что индекс не помещается в памяти. innodb_buffer_pool_size чему равен?
Ответ написан более трёх лет назад
Нравится 1 2 комментария
Дмитрий Скогорев @EnterSandman Автор вопроса
хех, дефолтные шышнацать мехабайт. Посоветуйте, пожалуйста, сколько в реальности стоит дать?

Дмитрий Скогорев: я бы начал с 500 мегабайт и смотрел. А вообще есть довольно простой вариант, либо выставляем 75% от RAM (либо, если на сервере не только mysql а еще что-то, 75% от того что остается) либо подобрать по даным. Для этого можно воспользоваться таким запросом:

SELECT CONCAT(ROUND(KBS/POWER(1024, IF(PowerOf1024<0,0,IF(PowerOf1024>3,0,PowerOf1024)))+0.49999), SUBSTR(' KMG',IF(PowerOf10243,0,PowerOf1024))+1,1)) recommended_innodb_buffer_pool_size FROM (SELECT SUM(data_length+index_length) KBS FROM information_schema.tables WHERE engine='InnoDB') A, (SELECT 3 PowerOf1024) B;

kuroneco

Системный администратор

Выполните: explain select id,value from table where limit 1;
И увидите, что пытается сделать оптимизатор. Используется индекс или нет.
Еще, что у вас за движок таблицы. Сколько занимает БД и таблица?

Ответ написан более трёх лет назад
Дмитрий Скогорев @EnterSandman Автор вопроса

Innodb, в таблице около 7 млн записей и 750Мб, остальные таблицы в базе ничтожно малы
стоит ли попробовать сделать разделение с range или использовать mongodb?

kuroneco

Дмитрий Скогорев: possible_keys показывает, какие индексы есть. колонка key, говорит, что индекс не используется.
Покажите вывод команды:
SHOW CREATE TABLE keys\G

А так же запросов:
SHOW VARIABLES LIKE ‘innodb_buffer_pool_size’;

Хотя, выше в комментарии, уже вижу что стоит дефолтные 16мб.
Вопрос следующий. сколько ОЗУ на сервере. На сервере только СУБД крутиться?

Дмитрий Скогорев @EnterSandman Автор вопроса

kuroneco: | innodb_buffer_pool_size | 1073741824 | выставил на 1гб.

Create Table: CREATE TABLE `keys` (
`userid` varchar(12) NOT NULL,
`value` varchar(12) NOT NULL,
PRIMARY KEY (`userid`),
UNIQUE KEY `userid` (`userid`),
KEY `userid_2` (`userid`),
KEY `userid_3` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

kuroneco

Дмитрий Скогорев: после того как поменяли innodb_buffer_pool_size, сервер рестартовали? Поменяли в my.cnf?
Не понятно, зачем вы создали userid_2, userid_3 на одно и то же поле. Уберите.
Почему у вас userid varchar а не int? или планируются еще буквы? Может ли быть userid автоинкриментом?
Если рестартовали и тот explain дает, что дает, то выполните вот такую команду и вывод сюда:

explain select userid,value from keys where userid=’4650017′ limit 1;

А также такой запрос

explain select userid,value from keys FORCE INDEX (PRIMARY) where userid=’4650017′ limit 1;

Дмитрий Скогорев @EnterSandman Автор вопроса

почему добавились userid_2_3 — вопрос к pma, видимо

Дмитрий Скогорев @EnterSandman Автор вопроса

kuroneco

Дмитрий Скогорев: понимаете, почему сейчас индекс сработал в 1ом случае?

kuroneco

Дмитрий Скогорев: Ну и естественно, если выполнить: select userid,value from keys where userid=’123499′; Ответ быстро выдастся. Лимит убрал, так как вы говорили, что у вас уникальные значения.

Дмитрий Скогорев @EnterSandman Автор вопроса

kuroneco: честно скажу — я не всё понял из того что делал. однако сейчас создал новую таблицу с userid int и value bigint, добавил только индекс на userid и теперь всё отрабатывает мгновенно.
выражаю благодарность за потраченное время

kuroneco

Дмитрий Скогорев: вы не правильно создали таблицу и делали не правильный запрос. Если ваш userid будет только числовым уникальным значением, нужно сделать его типа int not null auto_increment, чтобы он сам приращивал значение при insert. То, что мы делали с вами — посмотрели, как создана таблица и посмотрели как работает ваш запрос с помощью команды explain. primary key так же можно создавать на этапе создания таблицы или позже. Если его у вас нет, правильно создать его, а не лепить индекс. А проблема в вашем запросе была, из-за того что вы указывали userid = без кавычек. Для всех типов столбцов, кроме int,float и кажется чего-то еще, кавычки обязательны. Иначе, оптимизатор отправит ваш запрос в долгое путешествие на просматривание всех строк.
Вообще, если есть желание получить фундаментальные знания по составления запросов, таблиц и т.д, рекомендую книгу — Л.Бейли «Изучаем SQL». Очень легко читается. Наполнена юмором, сарказмом и игровыми моментами.

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *