Ответы пользователя по тегу MySQL
  • Fatal error: Allowed memory size. Как сделать запрос SQL чтобы не получать ошибку?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Читаем https://www.php.net/manual/ru/mysqlinfo.concepts.b...
    и делаем свой запрос небуферизованным.
    Ну и разумеется читаем все 300 офигиллиардов строк не сразу в массив, а обрабатываем по одной.
    Ответ написан
    6 комментариев
  • Как подключить одну базу к разным хостингам?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Разумеется, API.
    Сейчас даже в рамках одного "хостинга" многие проекты переходят на микросервисную архитектуру, ходя в лежащую рядом БД не напрямую, а обращаясь по НТТР к сервису, который уже и лезет в БД.

    Тем более что тут нужна не вся БД, а всего-то одна таблица. То есть код пишется за полчаса.
    На клиенте file_get_contents, на сервере такой же код, что и при обычной авторизации, но возвращает не Location а true.
    Ответ написан
    Комментировать
  • Как правильно распределить хранение комментариев?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Правильно все однородные данные хранить в одной таблице.
    Связи в БД строятся на основании содержимого таблиц, а не на основании их имён.
    Иначе потом приходится "бегать по всем этим таблицам и собирать записи".

    Так же при проектировании БД следует опираться на требования архитектуры, а не на влажные эротические мечты про "сумасшедшие масштабы". Если когда-нибудь проект достигнет сумасшедших масштабов, то к этому моменту вся архитектура будет переделана не один раз. И проблема комментариев будет решаться в зависимости от реальных проблем с которыми столкнётся проект, а не в соответствии с фантазиями, которые были у кого-то на начальном этапе.
    Ответ написан
    Комментировать
  • Как обновлять данные каждые 24 часа в MySQL?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Никак не увеличивать, при запросе добавлять к исходному значению число прошедших дней
    Ответ написан
    Комментировать
  • Как создать локальную базу данных?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    На mysql не создают такой файл.
    Mysql - это отдельная программа, которая хранит данные в своих собственных файлах.
    "Создавать" её не надо. На хостинге она уже есть, дома она обычно тоже уже есть, в составе какого-нибудь набора - XAMPP, MAMP и пр.
    Если никаких наборов нет, то скачать и установить Mysql с офсайта.

    После этого вся работа с БД будет производиться через SQL.
    Лучше это делать через нормальный клиент, типа PHPStorm, Workbench и так далее. В крайнем случае - phpmyadmin, но это конечно очень уродливая программа.
    Настроить программу на соединение с сервером БД и выполнять в нем команды SQL.
    Например, создать database - это типа такой каталог, в котором лежат таблицы - CREATE DATABASE mydb;
    И вот это mydb потом указывать в параметрах подключения PDO.
    Ответ написан
    Комментировать
  • Почему выдаёт ошибку? Подключился через MAMP PRO к локальному хосту и попытался реализовать форму регистрации, но выдаёт ошибку, почему?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Задавать вопрос "почему мой код не работает" бесполезно.
    Просто потому что код может не работать примерно по миллиону причин. Запаришься все перечислять.
    Причём эти причины к самому коду могут не иметь никакого отношения.
    Всегда надо задавать вопрос "как я могу узнать, почему код не работает".

    Чтобы узнать, почему РНР код не работает, надо прочитать сообщение об ошибке РНР. В данном случае мы его не видим, а видим только сообщение веб-сервера о том, что РНР завершился с ошибкой.
    Чтобы увидеть ошибку РНР, надо сделать две вещи:
    1. Убедиться, что РНР генерирует сообщения об ошибках. Для этого во-первых, всегда должен стоять максимальный уровень генерации ошибок, error_reporting(E_ALL);, и во-вторых, программист не должен сам себе стрелять в ногу, насильно подавляя сообщения об ошибках. И никогда не использовать оператор подавления ошибок, @.
    2. На время разработки поставить режим вывода ошибок на экран, ini_set('display_errors', 1);. На боевом сервере, соответственно, этот режим должен быть выключен, а логирование наоборот - включено.

    И только после получения сообщения об ошибке можно уже приходить на Хабр с вопросом. Но сначала предварительно погуглить, потому что все вопросы уже задавали по миллиону раз.
    В данном случае вероятной причиной может быть нестандартный порт mysql. Но опять же, гадать нет смысла, надо сначала увидеть сообщение об ошибке.

    Отдельно отмечу, что в таком виде регистрацию делать бессмысленно, тут сплошная SQL инъекция, то есть кто угодно сможет узнать чужой пароль, залогиниться под чужим именем или вообще зайти без пароля. Все SQL запросы, в которых участвуют переменные, в обязательном порядке должны выполняться через подготовленные выражения, с заменой переменных на знаки подстановки.
    Кроме того, пароль в обязательном порядке должен стойко хэшироваться, функцией password_hash()
    Ответ написан
    Комментировать
  • Как mysql/mariadb сортирует одинаковые значения?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    В целом п.3
    Обеспечивать случайность - это затратная операция, её никто просто так делать не будет. Скорее всего, имелся ввиду неопределённый порядок, а не случайный. Который как раз и подходит под п.3

    Если сразу после добавления, то может в порядке вставки, но это не точно, поскольку запись может идти не линейно, а на место записей, помеченных, как удалённые. Плюс после удалений/обновлений физический порядок записей в файле тоже может меняться, и соответственно, порядок выдачи.
    В целом ответ - никак не сортирует, берет первую попавшуюся.
    Ответ написан
    Комментировать
  • Почему один MySQL-сервер выбрасывает "Field 'some_field' doesn't have a default value", а другой просто инсертит пустое значение в 'some_field'?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Объяснение очень легко гуглится по тексту ошибки.
    За это поведение отвечает Mysql strict mode
    На одном сервере этот режим включён, на втором - выключен.
    Ответ написан
    1 комментарий
  • Оптимизация mysql, слишком большие таблицы?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Ну как минимум xtrabackup а не mysqldump.

    А в целом, я думаю, тут решение одно - нанять грамотного сисадмина/DBA
    Чтобы лечил причину, а не следствие (то есть разбирался - почему "крашнулась" таблица, и делал так, чтобы это не повторялось)
    Чтобы не писал ерунды типа "место кончилось" (как будто под линуксом проблема перекинуть файлы сразу на другую машину)
    А если уж и писал в Спортлото, то делал это чётко и подробно, с максимумом технических подробностей - какие физические характеристики серверов, какая операционка, какая БД, все версии с точностью до последней буквы, какой тип таблиц, с какой ошибкой "крашнулось", какую "ошибку" пишет при переносе.
    Ответ написан
  • Как реализовать добавление записи в связанные таблицы MySQL?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Точно так же, как и в любую другую. Добавление в связанную таблицу ничем не отличается от любого другого запроса INSERT.
    Только надо не забыть данные для добавленного поля.

    function textlog($connect, $chat_id, $text, $user_id) {
        if (!$chat_id) {
            return false;
        }
        $sql = "INSERT INTO textlog (chat_id, phone, user_id) VALUES (?,?,?)";
        $stmt = $connect->prepare($sql);
        $stmt->bind_param("sss",$chat_id, $text, $user_id);
        $stmt->execute();
        return true;
    }
    Ответ написан
    1 комментарий
  • Какой стэк использовать для быстрого доступа данных?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Для "доступа" использовать ту реляционную БД, которая имеется в наличии. При появлении проблем с производительностью - диагностировать их, и с конкретными вопросами приходить на Хабр.
    Для поиска - "быстрого", "по параметрам", полнотекстового - использовать предназначенный для этого движок, например Эластик. При появлении проблем с производительностью - диагностировать их, и с конкретными вопросами приходить на Хабр.

    spoiler
    Сам по себе ход мысли в вопросе очень характерный.
    Звучит примерно так: "Купил машину, что-то плохо тянуть стала. Думаю докупить упряжку лошадей, чтобы запрягать спереди. Лошадиные силы ведь прибавятся! Посматриваю ещё на воздушных змеев, лыжи, и дополнительный омыватель". То есть вместо простых и очевидных действий по диагностике, формулированию конкретных проблем, и последующему ремонту машины мы фантазируем себе набор каких-то бессмысленных и хаотичных телодвижений. Которые мало того что вообще никак не помогут, но скорее всего ухудшат ситуацию.

    И, разумеется, не приводим ни одной цифры, ни одного конкретного примера. Ни даже примерной нагрузки на систему - хоть в попугаях/посетителях. Ни загрузки процессора на серверах. Ни причин, по которым пришлось делать мастер-слейв. Ни текущей статистики по Mysql. Одни оценочные суждения, " А здоровье мое не очень. То лапы ломит, то хвост отваливается." Общие причитания про повышение нагрузки, "на запись и чтение". При том что запись уже больше не упоминается нигде, и непонятно - есть какие-то проблемы с ней, или нет. Да и с MySQL в целом.

    В итоге из всех невнятных жалоб становится понятно, что с самой БД, судя по всему, проблем нет. А есть только один участок, к которому есть вопросы - поиск. Есть идея реализовать его через Эластик, но есть сомнения. При том что Озон там, МВидео и прочих мастодонтов Эластик устраивает, а вот нашему магазинчику с 300К записей он не угодил. Сразу вспоминается анекдот про нового русского и 600-й мерс с засорившейся пепельницей. Не тянет Эластик? Будем менять на Монгу!

    Я думаю, что в таких ситуациях в первую очередь надо установить в систему здравый смысл. Перестать метаться с безумными фантазиями, а подойти к вопросу логически: есть вопросы к поиску? Значит надо поставить поисковый движок. поисковый движок - это в 99% случаев - Эластик. К нему есть вопросы? Отлично. Максимально подробно формулируем эти вопросы - не забывая привести индексы, конфиги, запросы - и задаём конкретный вопрос по оптимизации работы Эластика.

    А сейчас проблема "может мне монгу воткнуть?" проходит исключительно по разряду "Когда коту делать нечего, он гигиеной занимается".


    P.S. Не удивлюсь, если в итоге выяснится, что вся проблема сводится к истории, которая случилась в одном маленьком интернет-магазинчике: там тоже купили аж 3 сервера по 256Г мозгов в каждом, мастер-слейв, все дела... И не поменяли дефолтное значение innodb_buffer_pool_size в 128М. И что характерно, этот "кластер" даже тащил какое-то время, пока не случилась 10х нагрузка.
    Ответ написан
    2 комментария
  • Почему данные заказа не отправляются в базу данных?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Потому что вы вообще никак не отреагировали на те ответы, которые вам дали в прошлый раз на этот же самый вопрос.
    Вам написали, как правильно выполнять запросы. Вы это сделали?
    Вам написали, какие действия выполнять, если код не работает. Вы их выполнили?
    Вы так и планируете ходить на Хабр каждый раз, когда код не работает? Вот прямо серьёзно? Это, по-вашему, именно то, чем занимаются программисты?

    Пожалуйста, прочитайте ответы, которые вам давали на этот вопрос в прошлый раз и начните уже им следовать.
    Иначе программирование для вас так и останется игрой в прятки в темноте - "ой, что-то написала, не работает! Ой, что-то другое написала - работает!".

    К тому что написано в предыдущем ответе надо добавить только одно: перед
    new mysqli(...);
    надо всегда писать
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    чтобы база данных сама сообщала, почему не может выполнить запрос. Если дело именно в нём.
    Ответ написан
  • Как правильно объединить два запроса в один?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Правильно будет не объединять запросы в один без необходимости.
    Ответ написан
  • Как сделать так, что бы при пустом запросе в базу выводились ВСЕ значения?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    есть немного замороченный способ, но в целом он требует куда меньше кода
    WHERE (account_id=? OR ? is null)  AND (priority=? OR  ? is null)

    Чтобы его использовать, надо всего лишь передавать каждую переменную в запрос по два раза (и следить, чтобы пустые переменные содержали null).

    Другим вариантом является условная сборка запроса.
    Для этого мы собираем условия и переменные для них в массивы

    $conditions = [];
    $parameters = [];
    if ($account_id)
    {
        $conditions[] = 'account_id=?';
        $parameters[] = $account_id;
    }
    if ($priority )
    {
        $conditions[] = 'priority =?';
        $parameters[] = $priority;
    }

    собираем из условий запрос и выполняем его, привязывая все переменные разом
    тут из сложного будет привязка переменных из массива, но благодаря оператору распаковки аргументов это не так уж и сложно.
    if ($parameters)
    {
        $sql .= " WHERE ".implode(" AND ", $conditions);    
        $stmt = $db->prepare($sql);
        $stmt->bind_param(str_repeat("s", count($parameters)), ...$parameters);
        $stmt->execute();
        $result = $stmt->get_result();
    } else {
        $restult = $db->query($sql);
    }
    Ответ написан
    3 комментария
  • Как вытащить данные из stmt?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    вместо store_result(); надо писать get_result();
    этот метод даст вам привычный ресурс, из которого уже можно получить данные обычным способом
    $stmt = $link->prepare("SELECT * FROM users WHERE id=?");
    $stmt->bind_param('i', $value);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    Ответ написан
    5 комментариев
  • В чём ошибка подключения к безе по PDO?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Ошибку указывает сама PDO.
    Для этого в настройках надо указать PDO::ERRMODE_EXCEPTION - это уже сделано.
    После этого, в случае, если выполнение запроса завершится ошибкой, РНР об этом сообщит.
    Надо только, опять же, не забыть включить отображение (на домашнем компьютере) или логирование (на боевом сервере) ошибок РНР.

    Если же РНР никаких ошибок не выводит, то их и нет.
    Ответ написан
    4 комментария
  • Что нужно отправить на сервер, чтобы php понял это, как null?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Вопрос неверный. В стиле анекдота "у таракана уши в ногах".
    Разумеется, сервер всё прекрасно видит.
    чтобы РНР принял null, надо отправить на сервер null. Удивительно, но факт.
    var_dump(json_decode('{ 
        "name": ["i", "b"], 
        "val": [null]
    }',1));


    А вот что там делает код на этом сервере - никто не знает.
    И обращаться надо к автору кода. А не в Спортлото

    Скорее всего там либо array_filter, либо isset/empty($array['val']);
    Ответ написан
    4 комментария
  • Как получить список таблиц и полей без индекса (mysql), по которым происходит выбор?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Джинны и феи бывают только в сказках, дружок.

    Сидеть разбирать вручную каждый запрос через explain - именно так это и делается.
    Потому что само по себе механические впиливание индекса не решает вообще ничего.
    Оптимизация запроса - это далеко совсем не только "создать индекс на поле, по которому идёт выборка"
    Потому что этот индекс может не сработать
    Потому что может быть нужен совсем другой индекс.
    Потому что избыточные индексы могу наоборот замедлить приложение.
    Ответ написан
    Комментировать
  • Как сделать prepare запрос без bind_params?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Сначала я вообще ничего не понял, но поразмыслив, разобрался, про что этот вопрос.
    И поскольку он повторяет весьма распространённые заблуждения, то будет полезно на него подробно ответить.

    Можно ли как-то безопасно сделать такой запрос, который я соберу в строку?

    Нет, нельзя.

    Это распространённое, но очень смешное заблуждение. Если подумать, то само по себе prepare() ни от чего не защищает. Это не волшебное слово типа "Экспекто патронум!" - написал, и дальше уже можно не париться, оно само как-то магически защитит от инъекций. В реальной жизни таких слов ещё, увы, не придумали. А защищает именно замена актуальных переменных в запросе на знаки подстановки и последующая привязка через bind_param. А prepare просто говорит базе данных ,что запрос еще рано исполнять, это только схема запроса, а данные для него приедут позже.

    Я так понял, что если я выполняю $sql = $mysqli->prepare($request), то выполнится только один запрос, который первый, даже, если в него вложен будет второй, пусть я его строкой и засунул.

    Это тоже очень распространённое, и очень вредное заблуждение. Запрос выполнится только один, да. Тут всё верно. Но проблема в том, что SQL инъекция - это не один запрос
    INSERT INTO students (name) VALUES ('Robert');DROP TABLE students;
    , который рисуют в примерах для первоклассников. Инъекция - это любой посторонний код в запросе, вообще любой.

    Поэтому собирать в строку надо всё равно запрос со знаками подстановки, а потом его выполнить. Благо, в 5.6 версии пхп появился оператор распаковки параметров, который значительно облегчил эту задачу.

    Не хочется использовать лишние переменные и обработку для типов данных

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

    Для запроса, который приведен в примере, код будет относительно простым, поскольку заменяется на вызов IN:

    $names = ["Stepan" , "Stiv"];
    $in    = str_repeat('?,', count($names) - 1) . '?'; // получаем строку вида "?,?"
    $sql   = "SELECT * FROM users WHERE name IN ($in)"; // поставляем её в SQL
    $stmt  = $mysqli->prepare($sql); // prepare
    $types = str_repeat('s', count($names)); // получаем строку "sss" по количеству переменных
    $stmt->bind_param($types, ...$names); // привязываем наш массив
    $stmt->execute(); // выполняем
    $result = $stmt->get_result(); // дальше всё как обычно
    $data = $result->fetch_all(MYSQLI_ASSOC);


    Для более сложных запросов принцип будет тот же: собираем строку с плейсхолдерами, а переменные для неё - в массив. И потом выполняем так же через bind_param($types, ...$parameters);, как-то так:

    $conditions = [];
    $parameters = [];
    if (!empty($_GET['name']))
    {
        $conditions[] = 'name LIKE ?';
        $parameters[] = '%'.$_GET['name']."%";
    }
    // любое количество таких условий
    if ($conditions)
    {
        $sql .= " WHERE ".implode(" AND ", $conditions);
    }

    и дальше выполняем обычным порядком.

    Ну и в завершение, ответим на вопрос из заголовка буквально
    Как сделать prepare запрос без bind_params?

    Как правильно заметил TheAndrey7 в комментариях, начиная с версии 8.1 можно будет отправить переменные сразу в execute():

    $names = ["Stepan" , "Stiv"];
    $in    = str_repeat('?,', count($names) - 1) . '?';
    $sql   = "SELECT * FROM users WHERE name IN ($in)";
    $stmt  = $mysqli->prepare($sql); 
    $stmt->execute($names); 
    $data = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    Ответ написан
    4 комментария
  • Как убить ошибку Error Code: 1114. The table '...\#sqlc60_9_37' is full?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    alter table test add key (sec_code, class_code)
    и смотреть, уйдёт ли temporary из поля Extra в EXPLAIN

    И вообще - в первую очередь смотреть EXPLAIN, а не возиться с этой ерундой.
    и убирать using temporary ДО того как временной таблице перестанет хватать места на диске.
    Потому что у меня даже и без этой ошибки инфаркт будет, если я увижу такой запрос в продакшен коде.
    Ответ написан
    3 комментария