Transcription
в этом видео вы познакомитесь с основными сущностями и объектами в базе данных, о которых нужно знать, о которых спрашивают на собеседовании. видео будет разделено на две части. во второй поговорим о более продвинутых вещах типа шардирование, партиционирование, триггеры, функции. А в этом первом видео поговорим о базовых вещах, которые составляют фундамент знаний по базам данных, по SQL. посмотрим сегодня на кластеры, базы, схемы, таблицы. Что такое первичные, внешние ключи? Что такое ограничения? Что такое последовательности и как с ними работать? И, конечно же, в конце посмотрим на индексы. Очень часто спрашивают, что такое индексы, что такое индексирование, какие есть типы индексов, как они работают, для каких случаев они применяются. В общем, то, что спрашивают постоянно на собеседованиях.
в этом видео. Привет, друзья! Меня зовут Артём Шумейко, и на этом канале я помогаю айтишникам прокачивать хард скилы и развивать карьеру. Погнали!
и первое, что хочется обсудить, — это то, как вообще работать с базой данных. есть два популярных редактора или графических интерфейса для работы с традиционными базами данных. это PG Admin, именно для работы с PostgreSQL. PostgreSQL — это самая популярная СУБД, то есть система управления базами данных в мире. и есть так называемый DBeaver или DBeaver в простонародье. и мы будем пользоваться именно им, потому что в нём можно подключаться ко всем базам данных, там к PostgreSQL, Oracle, MySQL, ClickHouse, многие другие. там есть более классные автодополнения, там можно очень удобно работать с большими данными, редактировать данные, в общем, всё то, что нужно разработчикам, аналитикам и администраторам баз данных для удобной работы.
Итак, давайте перенесёмся в DBeaver. Ну, или я буду называть его DBeaver. И сразу здесь увидим подключение к PostgreSQL. у меня он локально развёрнут. у вас он также может быть развёрнут локально. у вас может быть другая реляционная база данных. в принципе, очень похожи у них сущности и называются, и работают, поэтому особых проблем с этим не возникнет. или вы можете подключиться к базе данных на внешнем сервере.
Давайте посмотрим, что есть внутри PostgreSQL. здесь есть база данных. и у вас сразу может возникнуть непонимание: "Стоп! Так PostgreSQL — это вроде уже и есть база данных. Как внутри PostgreSQL могут быть базы данных? Она же одна?" На самом деле, когда говорим про PostgreSQL, мы часто употребляем термин "кластер". и в сознании большинства людей, да, и у меня тоже, кластер — это когда много каких-то разрозненных, ну, или связанных вещей. и в PostgreSQL кажется, что, ну, наверное, на нескольких серверах там несколько PostgreSQL развёрнуто. на самом деле, нет. если мы говорим про PostgreSQL, кластер — это на одном сервере один запущенный экземпляр, можно сказать, PostgreSQL. и внутри можно плодить любое количество баз данных. у меня на одной из работ я видел три своих базы данных на одном кластере, и у других разработчиков с других проектов. и я даже не мог к ним подключиться. То есть то, что у вас есть доступ к кластеру, ещё не значит, что у вас есть доступ ко всем базам данных.
здесь есть база данных из прошлого видео по ACID. обязательно посмотрите, очень часто спрашивают про ACID на собеседовании. и для этого видео мы создадим новую базу данных. назовём её, например, NewDB. и вот так просто это делается. конечно, можно ещё задавать пароли, можно создавать новых пользователей, можно очень гранулированно давать права на базы данных, ко всем там схемам, таблицам. Но сегодня мы не будем заниматься администрированием. мы посмотрим больше на прикладные вещи, на то, чем пользуются разработчики, аналитики на повседневной основе.
что есть внутри базы данных? здесь есть схемы. и нам очень интересны именно они. также есть, конечно, роли, о которых я сказал, триггеры, расширения — это уже более административное управление, мы сегодня им не будем заниматься. в базе данных есть схемы. и может возникнуть вопрос: "Ну, как бы, а где таблица-то?" Ну, таблица на самом деле чуть дальше, уже внутри схемы.
Что такое схемы? Зачем они нужны? Если бы у нас были просто таблицы, то это была бы очень, ну, линейная, плоская структура, и не было никакой иерархии. Мы живём в мире, где у нас очень много разных иерархий, и мы хотим, например, в одной схеме хранить данные там для аналитиков, во второй схеме для разработчиков, в третьей там для администраторов, четвёртой для ещё какого-то там департамента и так далее. То есть можем делить по бизнес каким-то сущностям, по бизнес-командам. ещё из примеров: на одной из работ нам нужно было на бэкенде, собственно, бэкенд-разработчик на Python, тестировать наш код, наше приложение. это API, это различные функции обычные, и это заключение к базе данных, конечно. и чтобы не просить DevOps создать новую базу данных, выдать от неё там логин-пароль, что занимает, ну, я думаю, те, кто работают в больших компаниях, знают, очень много времени, неделю, две, или три, или больше. и у нас не было столько времени. и мы пришли к решению, что мы можем просто на время тестирования создавать новую схему под названием "test", туда переносить все данные из существующей схемы Public. схема по умолчанию называется именно так, Public, и обычно её не меняют. и переносили данные, на них тестировали, всё, потом схему и таблицы сносили. всё хорошо работает. и таким образом получилось очень удобно, быстро решить проблему с тестированием, не пришлось поднимать новую базу данных.
далее, что внутри схем? мы сегодня поработаем с одной схемой. можно, конечно же, опять создавать новые, сколько угодно и так далее. мы будем работать со схемой Public. на самом деле, разницы в схемах нету, и в названиях тоже нету. здесь есть очень много всего: таблицы, представления, от представления. на них мы тоже посмотрим в следующем видео. Сегодня у нас будут таблицы, индексы, последовательности и кое-что ещё. таблиц нету. их можно создать через графический интерфейс либо через SQL-запрос. и я больше привык создавать таблицы через SQL, поэтому давайте, собственно, здесь это и сделаем.
открываем редактор и пишем: CREATE TABLE. Давайте какой-нибудь, не знаю, users назовём табличку. и здесь напишем следующее. а мы, когда работаем с таблицами в базах данных, мы очень часто хотим иметь какой-то уникальный ключ, какой-то идентификатор для конкретной записи. это может быть транзакция банковская, это может быть ID пользователя, это может быть ID картинки какой-нибудь. то есть мы хотим к каждому объекту поставить какой-то ярлык, и чтобы по нему можно было очевидно понять, что это за объект. то есть, если у нас есть какой-то идентификатор, а, ну, значит, этот объект. и чаще всего такое поле называется ID, оно является первичным ключом так называемым, по которому можно определить, что это за объект. и мы указываем ему тип. мы можем указать ему тип, например, там просто integer. но мы бы очень хотели, чтобы база данных за нас самостоятельно генерировала. тип SERIAL или BIGSERIAL — это то же самое целое число, просто которое автоматически прибавляется с каждым разом, с каждой вставкой. то есть первая запись у вас будет иметь ID 1, вторая — два, третья — три, ну и так далее.
и давайте сразу ещё посмотрим на то, какие бывают, наверное, ограничения в базах данных. то есть, например, создадим. у пользователя есть имя, тип VARCHAR. мы не будем сегодня особенно останавливаться на типах, их очень много. там есть VARCHAR, есть CHAR, есть, например, TEXT. разницы между ними не так много для рядового пользователя. если вы разрабатываете высоконагруженную, большую систему, то, конечно, вам нужно лучше выделять там один байт под ячейку, а не четыре байта или не восемь байт. Но сегодня, опять же, не о [музыка] гипероплюс 150. и любые значения, которые выходят за эти рамки, не будут пропускать базы данных. просто будет выдаваться ошибка.
Давайте создадим базу данных и вставим парочку записей. это делать через INSERT, мы опять же сегодня не будем учить SQL. предполагается, что вы знаете, и это видео больше так подходит, наверное, для подготовки к собеседованию, либо быстро узнать какие сущности, вспомнить что-то, что уже давно забыли. кстати, друзья, если вы сейчас готовитесь к собеседованию и хотите понять, какие вопросы задают по базам данных, SQL, по вашему любимому языку программирования, там Computer Science, Git, Docker, в общем, все, все вопросы вместе с ответами собраны на сайте Solvit. Solvit — это ваш помощник в подготовке к собеседованию. там есть тренажёр собеседований, чтобы имитировать реальное собеседование. Приходите по ссылке в описании на сайт Solvit, готовьтесь к собеседованию и получайте самые крутые предложения о работе.
и мы вставим данные. пример в users. мы указываем столбцы. у нас есть name и age. и, например, давайте вставим там имя Артём, 24. и пускай будет какой-нибудь Бобёр, ноль. пускай Бобёр у нас молодой. и дальше мы можем посмотреть, какие у нас записи есть в таблице. и у нас есть две записи. Обратите внимание, у нас автоматически добавились ID к нашей таблице. то есть запись Артём имеет ID 1, запись Бобёр имеет ID 2.
и что это такое, на самом деле? что это за сущность? это сущность под названием "последовательность". у нас здесь слева есть последовательности. если их раскрыть, здесь обновить, что мы только что создали таблицу, у нас появится последовательность users_id_seq. ну, или seq — это типа sequence, последовательность. и здесь видно, с какого значения началась последовательность, какое было последнее значение — два, какое максимальное значение, после которого база, ну, мягко скажем, перестанет работать толком. а какой шаг и так далее. то есть вы можете конфигурировать, какие у вас будут ID, как они будут генерироваться.
и есть очень большая проблема в разработке, когда мы говорим про большие компании, большие проекты, уже отлаженные процессы. у нас есть много-много стендов или контуров или полигонов, называйте как угодно. там есть какой-нибудь тестовый, где сидят тестировщики, фронтендер, бэкендер. есть какой-то пре-продакшн, где сидят там продакт-менеджеры, продакт-менеджеры, пускай, и тимлиды. и есть продакшн, где уже сидят там тысячи, десятки тысяч, миллионов пользователей. и нам очень часто приходится данные переносить между стендами. ну, и под каждый стенд, естественно, есть какая-то своя база данных. мы хотим с тестовой на пре-продакшн базу перенести, с пре-продакшн на продакшн. очень часто последовательности разные. то есть где-то ID, не знаю, 150. в другой базе это 350. на продакшн базе это миллион с чем-то, потому что там записи просто больше. и мы можем управлять последовательностями, чтобы следующая запись, например, имела ID не 3, а 333. как это сделать? это можно, например, сделать через `SELECT setval`. дальше здесь мы указываем название последовательности `users_id_seq`. и дальше с какого ID-ника у нас должно начаться следующая, а следующая строчка. ну, например, пускай будет там какой-нибудь тысячный ID. да, вот мы переносим данные и понимаем, что, ага, у нас тут уже есть 999 записей, следующая должна быть тысячная. и здесь параметр `true`. и если мы занесём ещё одну строчку, например, пускай у нас будет здесь кот возрастом 3 годика, то обратите внимание, у нас будет 1001-я запись. если здесь поставить `false`, то у нас будет 1000-я запись. Вот так работают последовательности. с ними обычно работают, конечно, бэкенд-разработчики или администраторы баз данных, те, кто уже непосредственно работает с данными, работает с таблицами.
Если вы работаете на больших проектах, скорее всего, вы сталкивались с последовательностями. следующее, на что мы посмотрим и что очень удобно при разработке или аналитике, — это временные таблицы. как это делается? например, нам нужна какая-то табличка. мы хотим поэкспериментировать там с ограничениями, какими-то внешними ключами, типами данных. и мы не хотим видоизменять текущие таблицы, и мы не хотим создавать новую таблицу, потом забудем про неё, она останется. мы хотим создать временную таблицу вот сейчас, там, пока работаем с нашей базой данных. как это делается? мы пишем `CREATE TEMP TABLE`. то есть temporary, то есть временная таблица. и, ну, давайте её назовём как-нибудь Temp1. и дальше её наполняем какими-нибудь полями. ну, пускай у нас будет там тот же ID, SERIAL, PRIMARY KEY. и будет какой-нибудь value integer. всё, мы её создаём. она у нас есть. если мы обновим таблицы, то её не будет, потому что это временная таблица. мы сейчас можем здесь что-нибудь заселить, `SELECT * FROM Temp1`. она действительно есть. но если мы закроем этот скрипт, эту последовательность, откроем заново скрипт, ещё раз попробуем сделать `SELECT`, то у нас такой таблицы уже не будет, и нам придётся её заново создавать. временные таблицы часто используются аналитиками и иногда используются разработчиками для тестирования каких-то своих гипотез, работы с данными, с последовательностями в том числе. поэтому, друзья, обязательно пользуйтесь.
и следующая тема, к которой мы перейдём, — это индексы или индексирование таблиц в базе данных. это одна из самых сложных, глубоких тем, которую нужно действительно понимать, знать, как это используется, чтобы не навредить себе, другим разработчикам, пользователям. и сейчас мы посмотрим, что это такое.
одна из особенностей современных приложений — это постоянно растущий объём данных, который нужно хранить, передавать и обрабатывать. чтобы справиться с хранением и обработкой данных, компаниям нужны вместительные хранилища, системы хранения данных и гибкие базы данных. и всё это можно найти и арендовать в одном месте — Selectel. Selectel — это партнёр моего канала и один из ведущих провайдеров IT-инфраструктуры и облаков России, которому доверили свои данные уже более 25 000 клиентов. вся информация надёжно хранится в шести собственных дата-центрах компании. у Selectel широкий выбор сервисов для хранения под любую задачу и бюджет, от гибких облачных баз данных до ленточных систем хранения данных. в бэкенд-разработке последние годы всё чаще используются объектные хранилища. Selectel предоставляет собственное объектное хранилище, полностью совместимое с S3 и оптимизированное для работы с большими масштабами. у него нет лимита по объёму загруженных данных, так что не придётся беспокоиться о месте на диске. а ещё хранилище мультирегиональное, что повышает надёжность. а ещё к нему можно в пару кликов подключить CDN для ускорения доставки контента. сейчас Selectel — это можно сделать со стопроцентным кэшбэком и вернуть каждый рубль, потраченный на CDN, до 9 февраля. переходите по ссылке в описании и оставляйте заявку на консультацию, чтобы выбрать оптимальный сервис для хранения данных.
Итак, друзья, если вас спрашивают на собеседовании, что такое индексы или что такое индексирование, как нужно ответить? после ответа я покажу, собственно, как мы пользуемся индексами и какие типы индексов бывают.
Что такое индексы? Индексы — это какие-то некоторые сущности в базе данных, которые позволяют осуществлять очень быстрый поиск данных по таблице. это, по сути, единственный плюс индексов. и у индексов есть два основных минуса: первое — они постоянно пересчитываются, перераспределяются при вставке новых данных или обновлении данных, и второе — они занимают много места. то есть, если там столбец в базе данных занимает 100 МБ, индекс будет занимать тоже 100 МБ, просто чтобы вы понимали.
Теперь давайте посмотрим, что такое всё-таки индексы и как они позволяют нам быстрее искать данные. Давайте создадим табличку, назовём её T_Random, и вставим сюда огромное количество данных. создаём табличку и специальным скриптом. Давайте вставим сюда вот таким образом. Давайте посмотрим, сколько здесь данных: 10 миллионов строчек. то есть у нас будут абсолютно рандомные, просто текстовые строчки, не будет никакого в них смысла. и один из столбцов у нас первичный ключ, и второй столбец — value.
Итак, друзья, спустя одну минуту у нас создалась действительно таблица из 10 миллионов записей. Давайте посмотрим, как она выглядит. напишем `SELECT * FROM`. Не бойтесь, DBeaver не будет делать `SELECT *`, он не будет все 10 миллионов записей отдавать. он отдаёт их по 200 штук, он очень умненький. и здесь есть просто рандомные строки. и если листать вниз, вниз, вниз, то действительно их будет здесь 10 миллионов.
что здесь интересно? зачем мы сделали эту таблицу? индексы на самом деле нам нужны, когда у нас много данных. и много данных начинаются уже там от 10, 100 000 строчек, чтобы быстрее по ним искать. давайте сделаем два простых запроса. Давайте найдём строчку из T_Random, где ID равен, ну, пускай будет какой-нибудь там 87513. молниеносно, практически. вот здесь снизу видно: 0.002 секунды. и давайте попробуем найти какую-нибудь запись для столбца value, у которого там, ну, вот, например, вот это значение. запускаем и ждём целую секунду. то есть мы ждали в 500 раз больше, ну, грубо говоря. если хочется точных цифр, то можно вбить. здесь, кстати, тоже очень часто использующийся и аналитиками, и разработчиками запрос. мы увидим, что здесь время исполнения 0.027 миллисекунд. а если сюда добавим и запустим, то у нас здесь будет 185 миллисекунд. можем ещё несколько раз запустить и посмотреть, что у нас время запуска меняется. вот 150 миллисекунд. можем какую-нибудь другую белиберду внести. и, ну, примерно, да, столько времени занимает.
если сравнить два этих запроса по времени исполнения, то запрос на поиск по ID в тысячи раз быстрее, чем по столбцу value. в чём разница? разница в том, что столбец ID проиндексирован, потому что здесь есть первичный ключ, он уникальный. уникальный — это уже индекс, индекс уникальности. и у нас есть значение value, и на него нет никаких индексов. это просто обычное текстовое поле. и мы можем вкладывать индексы. это делается очень просто. мы пишем команду `CREATE INDEX`. дальше какое-нибудь название индекса. например, у нас есть таблица T_Random, столбец value, и idx часто так называется. дальше таблица о T_Random, и дальше мы прописываем название столбца — столбец value. и запускаем. и создание индекса требует времени, потому что он проходится по всей десятимиллионной таблице, все значения себе забирает и перераспределяет их таким образом, чтобы по ним было удобно искать. прошло буквально 20 секунд. у нас создался индекс. и если бы мы записали `USING btree`, ничего бы не изменилось, да. то есть по умолчанию всегда стоит индекс под названием B-tree. чуть позже поговорим о нём.
Давайте теперь ещё раз сделаем запрос на выборку. помните, в тот раз у нас занимало 160-170 миллисекунд? запускаем вот эту историю: 1 миллисекунда. даже, даже смотрите, даже ещё меньше. ну, потому что, скорее всего, она закешировалась. давайте какую-нибудь найдём рандомную запись. ну, какую-нибудь вот такую. мы по ней ещё ни разу не искали, ни в каком кэше там случайно оно нигде не закешировалось. исполним. бам! 1 миллисекунда. ну, и если дальше исполнять, то уже в кэше действительно оно занимает меньше времени. но было 170-180 миллисекунд, стало 1 миллисекунда. почти в 200 раз мы ускорили время получения ответа от базы. и это просто шикарно, это очень здорово. но можно ещё лучше.
Давайте перед тем, как говорить, что за индекс B-tree, давайте сделаем ещё один индекс. Давайте, во-первых, посмотрим на индексы. вот здесь у нас есть сейчас два индекса, даже три. у нас есть для users. мы когда с вами создавали таблицу users, у нас автоматически создался индекс на первичный ключ. когда мы создавали таблицу Random, у нас тоже автоматически создался первичный ключ. вот здесь видите PK, то есть первичный, primary. и мы создали с вами индекс на столбец. давайте этот индекс удалим пока что, он нам не нужен. и создадим, используя hash-индекс. это ещё один тип индекса. тоже нам придётся подождать некоторое время. тот занимал порядка там 18 секунд. ну, этот займёт примерно такое же время.
Итак, спустя примерно 22 секунды, также у нас создался индекс. он, естественно, появился ещё и здесь. и давайте посмотрим, какое сейчас время будет. то есть до этого у нас была 1 миллисекунда. давайте вобьём здесь какую-нибудь полную белиберду, с которой мы не работали, и посмотрим, сколько сейчас займёт время. запускаем: 0.5 миллисекунд. в 20 раз быстрее, чем предыдущий индекс. давайте ещё очень нибудь в объём. то есть я вбиваю абсолютно рандомные строки, которые, давайте вот текст введём, которых естественно нету в этой таблице. Но от этого смысла не меняется. я мог бы сюда внести какое-то значение, которое есть в таблице, и мог бы вносить значение, которого нет в таблице. в любом случае индекс очень быстро отрабатывает. давайте запустим ещё раз этот скрипт: 0.23 миллисекунды. ну, если я буду запускать его ещё раз, он будет в кэше. ну, короче, суть вы поняли. тот индекс нам в 200 раз B-tree принёс производительность. этот ещё в 50 раз. почему, спросите вы? в чём вообще разница?
Друзья, давайте посмотрим, что такое B-tree. очень простым языком. B-tree, как можно догадаться, и слово "tree" — это дерево. а B — это сбалансированное (balanced). и на примере вы видите, ну, какой-то аналог сбалансированного дерева, где у нас, например, идёт поиск по какому-то числу. например, мы хотим найти, а есть ли число, там, не знаю, 10, в нашей базе данных, в нашей таблице, в нашем столбце. как происходит поиск по таблице, когда нет индексов? база данных просто по всей таблице идёт, по всем 10 миллионам записей. это капец как долго. а если есть формат дерева сбалансированного, то есть в левой и правой части всегда одинаковое количество примерно строчек, то у нас с каждым погружением внутрь дерева, внутрь узлов, в два раза меньше становится записей, по которым мы ищем. то есть, например, смотрите, как это работает. я хочу как пользователь десятку: `SELECT * FROM T_Random WHERE value = 10`. как идём по сбалансированному дереву? сначала мы приходим в наш корень дерева, смотрим 25. Ага, значит, нужно идти левее. идём вот сюда, обнаруживаем 12. дальше понимаем: так, нам нужна десятка. десятка меньше чем 12, идём вот сюда. Ага, шестёрка. значит, нам нужно идти направо. смотрим, здесь есть только девятка, например. справа от девятки идём, там нет десятки. всё, мы понимаем, десятки нет. Или там десятка есть, мы отдаём десятку. то есть мы вместо того, чтобы проходить по абсолютно всем узлам, везде проверять: "Ребят, скажи, нет ли десятки? Нет ли десятки?" мы просто самым крачайшим путём дошли до значения 10 и его там нашли. Ну, да, мы искали не по числам, мы искали по строчкам, но разницы здесь особо нет. строчки тоже можно сравнивать, если что, там меньше, больше, оно также работает.
и теперь давайте посмотрим на hash-индекс. как это работает? если вы знакомы с хэш-функцией, это замечательно. хэш-функция по сути берёт какое-то значение. то есть у нас есть, например, какая-то строчка в нашем случае столбец называется value, и у нас есть какие-то строчки. каждая строчка при подсчёте индекса, то есть когда мы создавали индекс, вот те 22 секунды, которые шли, как раз-таки каждому значению применялась хэш-функция. для каждого значения столбца появлялось какое-то значение хэша. а это, на самом деле, адрес местоположения этих данных, ну, грубо говоря, на жёстком диске. таким образом база данных знает сразу же, на какую строчку ей нужно телепортироваться. то есть, если она видит, что пользователь написал запрос `SELECT * FROM таблица WHERE John_Smith`, она сразу понимает: "А, John_Smith, вторая ячейка, бам, отдаёт сразу данные". А B-tree, как мы с вами до этого обсудили, пошёл бы по нодам, делал бы очень быстро. но hash-индекс в 50 раз быстрее, чем B-tree, чем сбалансированное дерево. то есть hash-индекс работает идеально, просто волшебно, когда у нас есть запросы по типу "равно что-то", где значение равно чему-то. то есть здесь Лиза Смит, вот здесь будет сразу Сандра. здесь очень быстро срабатывает.
но вы можете спросить: "Артём, а почему тогда вот, когда мы создавали индекс по умолчанию, он был B-tree? Почему B-tree использовался по умолчанию?" ты сказал, что вот, если не использовать `USING`, будет сбалансированное дерево. просто потому, что в бизнесе, в разработке, в аналитике чаще всего встречаются запросы, где у нас есть не "равно", а где у нас идёт сравнение. Например, у нас есть там таблица пользователей, и нам нужно отдать всех пользователей, у которых возраст меньше чем 10 или больше чем 20. это всегда сравнение какое-то. и в hash-индексе это было бы неуместно. hash-индекс по конкретным значениям ищет. и в случае с неравенствами hash-индекс, скорее всего, даже бы не применил. то есть база данных поймёт, что да, есть какой-то индекс, но как будто бы он вообще не подходит сюда, я не буду его использовать. а в случае сбалансированного дерева, оно идеально подходит для неравенств. именно поэтому B-tree является индексом по умолчанию.
Давайте ещё раз подрезюмируем про индексы, что это за вещь и зачем она используется. индексы — это некоторые такие сущности, структуры данных, если более точно, в базе данных, которые позволяют быстрее искать данные в таблицах. они это делают за счёт своих необычных структур данных, собственно, это какая-то хэш-таблица, или это сбалансированное дерево, или это ещё другие типы. сейчас о них немножко скажу, по которым очень быстро производится поиск, там либо за логарифмическое время, либо за константное время. и это, это, конечно, плюсы. но есть и минусы в том, что индексы занимают довольно много памяти, и то, что при каждой вставке данных, например, новый `INSERT` или новый `UPDATE` или `DELETE`, происходит сбалансированное дерево или там хэш-таблицу приходится пересчитывать. из дерева убирать какую-то ячейку или добавлять новую. и раз дерево сбалансировано, его нужно ещё перебалансировать, чтобы слева, справа было одинаковое количество ячеек. и то же самое касается хэш-таблицы. там, конечно, чуть быстрее происходит перебалансировка. тем не менее, это требует времени. поэтому в нагруженных системах, ну, это уже больше мы в системный дизайн погружаемся, когда у нас очень большая нагрузка на запись, то есть у нас система вся на запись, там какие-то логи хранит, потребляет, или там вот какая-нибудь Яндекс.Метрика, которая собирает метрики со всех сайтов в интернете.
если вам интересно послушать про реальное применение индексов, про то, что у нас такое реплика мастер, как у нас масштабируется база данных, как у нас в принципе строится архитектура больших приложений, обязательно подписывайтесь на мой Telegram Артём Шумейко, ссылочка в описании, и следите за новыми курсами, видео и постами, в которых я буду рассказывать про большие системы, как их строить и как делать их надёжными и отказоустойчивыми.
на этом на сегодня всё. спасибо за просмотр и пока!