РЕАЛЬНОЕ Golang СОБЕСЕДОВАНИЕ на MIDDLE BACKEND РАЗРАБО… — Transcript

Собеседование на middle Go-разработчика в финтех с задачами по Go и SQL, разбор слайсов, мап, многопоточности и баз данных.

Key Takeaways

  • Слайсы в Go — это динамические структуры с указателем, длиной и емкостью, передаются по значению, но значение — ссылка.
  • Изменения слайса внутри функции могут быть видны снаружи, если изменяется базовый массив, но присваивание нового слайса локально не влияет на внешний.
  • Использование float для ключей в мапах и для денежных значений не рекомендуется из-за проблем с точностью и уникальностью.
  • Для хранения денежных значений лучше использовать целочисленные типы, умножая на минимальную денежную единицу (например, копейки).
  • В Go для синхронизации многопоточных операций применяются мьютексы и другие примитивы, а SQL-запросы требуют правильной сортировки и пагинации.

Summary

  • Видео демонстрирует реальное собеседование на позицию middle Go-разработчика в финтех-компании с зарплатой 300к рублей.
  • Обсуждаются задачи по Go, включая работу со слайсами, передачу данных в функции и особенности append.
  • Разбираются тонкости работы с мапами в Go, проблемы с ключами и хранением данных типа float.
  • Обсуждается правильное хранение денежных значений в базах данных и почему используют int вместо float.
  • Проводится теоретический разбор слайсов, их структура и поведение при передаче в функции.
  • Затрагиваются вопросы многопоточности, синхронизации с помощью мьютексов и работа с горутинами.
  • Обсуждаются SQL-запросы, сортировка, пагинация и работа с индексами, включая кластерные индексы.
  • Дается помощь в подготовке к собеседованиям, составлении резюме и менторстве для разработчиков разного уровня.
  • Видео содержит живое общение и объяснения, что помогает понять реальные ожидания работодателей.
  • Включены практические советы по улучшению самопрезентации и навыков кодирования.

Full Transcript — Download SRT & Markdown

00:00
Speaker A
Всем привет. Это новое видео с собеседованием на middle Go-разработчика в финтех-компанию с зарплатой 300к в месяц. Требования по вакансии вы можете видеть на экране.
00:11
Speaker A
Если тебе нужна помощь в трудоустройстве, смене работы или подготовке к собеседованиям, то можешь воспользоваться моими услугами менторства. Опытным разработчикам я составляю резюме, помогаю с подготовкой к собеседованиям и улучшением самопрезентации.
00:26
Speaker A
Для тех, кто приходит с нуля, даю чёткий roadmap не только с теорией, но и практическими заданиями, а также регулярными моксобеседованиями и кодревью.
00:35
Speaker A
Подробные условия ты можешь найти в закреплённом комментарии или в описании под этим видео. Ладно, у меня из общих вопросов, наверное, всё. Илья, может, хочешь что-нибудь спросить или перейдём к основной части?
00:49
Speaker A
Давай к основной. Хорошо. Так, смотри, сейчас я скину тебе в Zoom ссылочку. Зайди в неё, попробуй что-нибудь написать.
01:00
Speaker A
Работает, не работает?
01:25
Speaker A
Да, зашёл.
01:44
Speaker A
Так, проверили. Да, пишет всё хорошо.
01:54
Speaker A
Так, давай с первой задачкой. На разогревчик немножко поиграемся в компилятор.
02:13
Speaker A
Угу. Вообще, что видишь и что выведет программа?
02:29
Speaker A
Так, ну, у нас тут функция main. Мы создаём слайс с длиной три, capacity четыре.
02:54
Speaker A
[вздыхает] Так, слайс. И потом для нулевого, первого и второго присваиваем значения 1, 2, 3.
03:56
Speaker A
То есть, по идее, у нас тут так: номер 1, 2, 3.
04:21
Speaker A
Так, потом вызываем функцию modifySlice. Туда передаём уже наш слайс.
04:38
Speaker A
И внутри modifySlice мы присваиваем аргументу S новое значение, которое создаётся после append.
04:45
Speaker A
Так, здесь у нас S равен...
04:57
Speaker A
Так, S равен 1, 2, 3, 4.
05:18
Speaker A
Так, по идее, у нас аллокация не должна происходить, поэтому длина будет четыре, capacity четыре.
05:30
Speaker A
Так, и на пятнадцатой строке мы присваиваем S[0] равно 100.
05:46
Speaker A
Так.
05:58
Speaker A
Так, так. А что у нас на десятой строке выведет?
06:13
Speaker A
На десятой строке, по идее, у нас должно вывести 1, 2, 3, 4.
06:41
Speaker A
М.
07:06
Speaker A
Так, сейчас ещё раз проверю.
07:25
Speaker A
М.
07:42
Speaker A
Угу. Ну, в принципе, да. Это окончательный ответ.
07:58
Speaker A
Так будет, короче, потому что то, что вернула append — там новый, так скажем, указатель на слайс или что-то такое, он будет присвоен именно локальной переменной S, а не нашей S,
08:15
Speaker A
которая в main создалась, поэтому за пределами функции его не будет видно. Но всё равно этот новый S будет указывать на тот же массив, что и в main. И поэтому, когда мы его изменяем, изменения будут видны и в main. Ну, то есть нулевого элемента.
08:31
Speaker A
Окей.
08:44
Speaker A
Так, то есть получается окончательный ответ — это 100, 2, 3, 4. Правильно я понимаю?
09:01
Speaker A
Да.
09:11
Speaker A
Так, ты тут совершенно прав. Давай немножко по теории. Ты говорил, что вот на шестой строке мы создаём слайс. Что вообще такое слайс?
09:20
Speaker A
Угу. Слайс — это, так скажем, такой динамический массив в Go. Динамический за счёт того, что мы можем добавлять новые элементы в него. Ну и по сути это указатель на структуру. В структуре у нас слайса три поля. Первое — это указатель на базовый массив. Второе — это length. Третье — capacity.
09:31
Speaker A
Ну, длина — это длина массива, сколько в нём элементов. Capacity — это объём, так сказать, до которого у нас может увеличиваться длина без аллокаций.
09:54
Speaker A
Если уже длина равна capacity, мы делаем append, то там будет аллокация, и capacity либо в два раза увеличится, либо на 25%, если там меньше 1.24 элемента уже или больше.
10:05
Speaker A
Окей, хорошо. А как функции вообще передаются вот такие типы данных, как слайс, массив, может быть, структура?
10:26
Speaker A
Ну, слайс передаётся, можно сказать, по ссылке. Массив [вздыхает] передаётся по значению. Хотя, по-моему, говорят, что в Go всё передаётся по значению. Просто значением является ссылка на слайс.
10:36
Speaker A
Угу.
10:44
Speaker A
Так. И получается, когда мы в функцию modifySlice передаём какой-то определённый слайс, то у нас передаётся что?
11:06
Speaker A
Мм, ну, передаётся [вздыхает] ссылка на ту же структуру слайса, где указано будет, мм, где будет, короче, указатель внутри на тот же базовый массив, что и на шестой строке.
11:32
Speaker A
Окей, всё хорошо. Тут ты прав совершенно. Давай такой вопрос со звёздочкой. Смотри, не меняя функцию modifySlice вообще никак, а можно ли как-то сделать так, чтобы в main вывелось 100, 2, 3, 4?
11:47
Speaker A
Так, не меняем S, чтобы в main вывелось 100, 2, 3, 4.
12:02
Speaker A
Так, сейчас подумаю.
12:37
Speaker A
М, не знаю, не меняю modifySlice. Не знаю, только если в самом main это делать. То что в modifySlice? Ну или modifySlice может передавать как-то там указатель.
12:48
Speaker A
А нет, смотри, давай подумаем. Ну, на самом деле, ээ, как ты думаешь, когда мы добавили ему цифру четыре в, ну, к нашему изначальному слайсу, когда мы добавили ему цифру четыре в modifySlice, она вообще там осталась?
13:02
Speaker A
Мм, ну да, осталась. У нас длина три, поэтому мы не увидим. Ну, то есть получается S[4], если мы возьмём, то у нас или какая там, да, четвёртая, у нас произойдёт паника, правильно?
13:22
Speaker A
По идее, да, будет паника out of range.
13:46
Speaker A
Ну, короче, на самом деле, я не знаю, если честно, не особо мне интересно, почему это работает, но если вот дописать вот так, это сработает. Там не будет паники, он просто выйдет. Ну, это такой вопрос с подковыркой. Мало кто вообще в целом, наверное, будет использовать. Ну, хотя чисто в теории это рано или поздно может стрельнуть.
14:02
Speaker A
Вот программа, что выведется?
14:24
Speaker A
Так, по идее, мы тут создаём dictionary.
14:37
Speaker A
Так, dictionary у нас слайс строк.
14:46
Speaker A
Так, а в main мы создаём мапу, где ключами у нас float32, значение string.
15:08
Speaker A
Так и вызываем функцию insertData.
15:27
Speaker A
Так, внутри insertData у нас происходит [фыркает] range по мапе.
15:43
Speaker A
Угу.
15:49
Speaker A
Так. И мы вставляем value в эту мапу.
16:01
Speaker A
Так. Ну и в конце выводим [фыркает] значение мапы.
16:19
Speaker A
Так, ну, у нас будет четыре итерации: 1, 2, 3, 4.
16:37
Speaker A
Так, в каждой итерации у нас будет, ну, порядка, короче, не будет в этих ключах и значениях dictionary. И на каждой итерации мы в currencies вставляем какой-то рандомный float32 в качестве ключа и туда вставляем value.
16:56
Speaker A
Так. По идее, выведется мапа, где будет четыре рандомных ключа и будет значение из этого слайса.
17:12
Speaker A
Да, всё верно в целом. Только не понял, в чём подвох.
17:19
Speaker A
Ну, тут вот на самом деле я не знаю, может, можешь ли ты найти проблему, которая может возникнуть чисто в теории вообще? Есть ли тут, может быть, проблемы?
17:29
Speaker A
Так, ну, помню, что на map многие ругаются, что он там генерирует неуникальные числа, например.
17:42
Speaker A
Может, он там несколько одинаковых ключей сгенерит, и у нас меньше ключей окажется в currencies.
17:54
Speaker A
М, ну, точнее, мы перепишем какой-то ключ. [вздыхает]
18:06
Speaker A
Ну, на самом деле, да, ты абсолютно прав. Это единственный подвох, который здесь есть. Давай вот немножко подумаем, насколько правильно вообще... ну, как ты можешь заметить, здесь у нас вот массив, э, ну, как получается на выходе мапа, условно там, э, как это, мм, курсам валют, там USD, евро, там GBP, я там точно не помню. Как ты думаешь, насколько хорошо хранить её во float? И вообще, как это, может быть, есть какие-то мысли о том, как это лучше делать?
18:29
Speaker A
Угу. Ну, наверное, удобнее было бы хранить всё-таки, э, в качестве ключа именно курс валюты и значением уже какое-то значение этой валюты.
18:50
Speaker A
Угу. А вообще в целом вот float хорошо ли использовать там, если у нас какие-то валютные операции [фыркает] происходят? Ну, есть ли какие-то вообще, может быть, проблемы в этом? Какие проблемы видишь?
19:19
Speaker A
Так, сейчас подумаю. Наверное, не скажу, как-то не сталкивался с таким.
19:39
Speaker A
Хорошо, давай вот наводящий вопрос. Если на мысли не наведёт, то без проблем. А смотри, я знаю, что в, кажется, в Сбербанке вся БДшка хранит, да, ну там числа как это сумму денег там пользователя, условно на счетах. Она хранит их в int. Ну там может быть там 32, 64, тут точно, но точно в целых числах.
19:58
Speaker A
Как ты думаешь, почему это так и почему бы не хранить там float32, там, чтобы у тебя на счету условно было 1.000 руб. 32 коп? Почему они это там умножают условно на 100 и хранят в int?
20:12
Speaker A
Какие вот проблемы могут возникнуть?
20:27
Speaker A
Угу. Мм. Наверняка там какая-то есть проблема, связанная с точностью этих м, там всяких знаков после запятой.
20:42
Speaker A
Возможно. Мм, да, всё верно. Ээ, а почему? Я не знаю, насколько, но тут я такой чуть-чуть обширный вопрос. Вообще слышал, как вообще хранятся эти данные, как хранится float, может быть, там точно ли там, если ты забил там ноль, float32, float64 или может быть какие-то...
20:50
Speaker A
О'кей. Тогда давай про многопоточность в Го поговорим более подробно. [откашливается] Сейчас, секунду, я скопирую.
21:02
Speaker A
А вообще с многопоточностью в гол? Ну да конечно. Давай вообще какие сущности используются вот там в рамках многопоточности помимо там гурутинок?
21:17
Speaker A
Что вообще можешь рассказать там как происходит работа? С какими сущностями приходится работать? Угу. Так, ну, помимо грутин у нас типа есть, ну, вот как в задачке канала, например.
21:32
Speaker A
Ну, и вообще много примтивов синхронизации различных, там, например, атомики, ксыг группы, erр группы, наверное. Так, ну давай, что можешь вообще рассказать про каналы? Какие виды бывают?
21:51
Speaker A
Что, зачем, почему? Так, ну, каналы - это такие примитивы синхронизации. Могут быть буферизированные, не буферизированные. Нужны они для обмена данными в основном между рутинами.
22:05
Speaker A
Разница между буферизированным и небуферизированным в том, что когда мы пишем его небуферизированный, мы ожидаем, что у нас будет уже читатель.
22:15
Speaker A
Если читатель нет, то мы на записи заблокируемся. И также у нас с чтением, если нет того, кто пишет, чтение блокируется, потому что там данные в небуферизированном у нас нигде не хранятся, они передаются, так скажем, напрямую нагарути на рутине. А вот в
22:34
Speaker A
буферизированном там мы при мм при записи можем не блокироваться, если у нас буфер не заполнен.
22:45
Speaker A
И также при чтении у нас блокировка будет происходить только, если буфер пустой. Также можем итерироваться, точнее рейнджиться по каналам. Рейндж закончится, если мы канал закроем.
23:02
Speaker A
М, ну, в принципе, как-то так. О'кей. А направление каналов зачем вообще задавать? Угу. Ну, направление - это, можно сказать, ограничение на уровне типа.
23:16
Speaker A
Типа можно задать там readли либо write only, чтобы, так скажем, семантически было понятно, как мы хотим использовать и предполагаем, как использовать пользователь. Этой функции будет данный канал, потому чтобы только писал либо только читал, чтобы там не мог закрыть и
23:33
Speaker A
так далее. О'кей, хорошо. Так, по каналам понятно. Так, что у нас там есть? Вейт группа вообще зачем нужна?
23:44
Speaker A
Пользовался ли? Давай так. Ну да, йтгруппа нужна, чтобы у нас чаще всего дождаться выполнения каких-то операций, прежде чем перейти к какому-то другому блоку кода. Там у нас есть методы вг м, то есть добавляем какое-то количество операций, которые хотим дождаться. Гадан
24:08
Speaker A
вызываем, когда операция завершилась. Игавейт вызываем, чтобы заблокироваться, пока не выполнится все операции, которые мы хотим дождаться.
24:21
Speaker A
Угу. О'кей, хорошо, тут я понял. Спасибо. Про мютексы что можешь рассказать? Так, ну это тоже примитив синхронизации.
24:34
Speaker A
У нас есть там два метода основных - это log и unlock. Logем, мм, чтобы войти в какую-то критическую секцию кода, которую хотим мы выполнить, а, unlock, чтобы выйти из этой критической секции.
24:54
Speaker A
ЛК может захватывать только одна рутина. То есть в какой-то критической секции у нас может выполняться только одна грутина. Это у нас позволяет защищаться от каких-то датарейсов, например.
25:07
Speaker A
М, ну датарейсы - это когда мы обращаемся там, например, к одному м адресу памяти из нескольких рутин и хотя бы одно обращение - это запись.
25:18
Speaker A
Есть ещё там RVMEX. Он позволяет нам из нескольких рутин одновременно читать под эрлоком. Но на запись, когда запись сделаем, там тоже ставим лок обычно.
25:31
Speaker A
[вздыхает] И тут уже только одна рутина может выполняться. Так, о'кей, хорошо, я понял. Ладно, я не буду больше тебя мучить теории. Давай, давай, наверное, больше на практике посмотрим. В общем, смотри, есть функция fake download. По факту, что она
25:50
Speaker A
делает? Это имитирует загрузку с каким-то определённым шансом она выдаст нам ошибку, а либо какой-то определённый там результат, грубо говоря. там имитация того, что мы из какого-то ресурса качаем. У нас есть сама функция download. Нужно написать её так, чтобы
26:11
Speaker A
мы параллельно качали данные из урло, ну, с этих урлов при помощи функции fake download.
26:18
Speaker A
возвращаем мы массив слайстрок соответственно те которые мы удалось скачать, либо одну общую ошибку, если там ошибок несколько, если случилось при загрузке несколько ошибок, соответственно, нам нужно их склеить в одну большую.
26:38
Speaker A
Угу. Вот. А если всё понятно, пиши. Если возникнут вопросы, там, очевидно, задавай какие-то уточняющие.
26:59
Speaker A
Угу. Так, блин, только не помню, как склеивать ошибку. По-моему, там есть join. Окей, наверное, потом разберёмся. Ну, на самом деле, да, ты совершенно прав. Там есть er join. Тут ещё такой вопрос, мало кто на него кто вспоминает вообще про
27:23
Speaker A
такую функцию. Я-то помню, но не помню, какой у неё синтаксис там, что в ней происходи.
27:29
Speaker A
Да, слушай, я думаю, что здесь проблем там синтаксис, не синтаксис. Важно, чтобы ты в целом понимал, как это работает. Но там синтаксис, очевидно, тебе либоеха подсветит, либо там уже на короняк в интернете посмотришь. Так, fake download мы не
27:44
Speaker A
изменяем, мы просто передаём л в него. Да, да, да. Мы можем менять только функцию про Угу.
27:55
Speaker A
Окей. Так, я бы записал, что возвращать должно. Download Strings. Это это что такое? Это вот данные, которые возвращается нам из функции fake download. То есть там, если ты сейчас посмотришь, она возвращает структуру result, у которого есть message и error. Соответственно,
28:29
Speaker A
как бы, э, с с первый возвращаемый массив - это вот слайс слайснгов, который вот из result. MSG.
28:43
Speaker A
Угу. Вот так. О'кей. Так. Так, так. Но предварительно будем рейджиться по слайсу. Поставим там вейт группу, создадим слайс строк.
29:56
Speaker A
Слайс строк с мютоксом и как будто должно сработать. Так. Так. А порядок в Слайсе должен быть равен порядку юрлов?
30:50
Speaker A
Нет, нам абсолютно неважно. Главное, чтобы мы просто всё скачали. Угу. Так. Думаю, может хранить слайс результатов, потом в конце просто рейнджем пройтись и уже там определять, что возвращаем ошибку Или, ну, целом, в целом это должно сработать.
32:31
Speaker A
Плюс мы не перегружаем там гофункцию. Да, давай так. Так. Так, а если хоть одна ошибка есть, мы в Messengers что-нибудь должны возвращать?
35:09
Speaker A
То есть первому? Да, мы должны вернуть то, что мы успели скачать, и плюс ещё ошибку какую-нибудь.
35:18
Speaker A
Угу. Тут можно, конечно, сразу там выделить н равный рес и по индексам обращаться и изменять.
36:13
Speaker A
Ну я, короче, через опн сделаю. Ну, в целом я вообще никогда не видел, что вы там по индексу что-то делали. Я не знаю, я видел только через appнд.
36:31
Speaker A
Так надо сол А ты сейчас, подожди. А, извиняюсь. Так, я посмотрю сейчас, как Join работает.
37:09
Speaker A
Подожди стадовании не пользуемся интернетом. Если что-то не знаешь, как бы просто можешь там написать псевдокодом, что типа джойним здесь ошибку.
37:22
Speaker A
Поэтому так возращ я что-то позабыл. Если у нас первая ошибка встретилась, мы продолжаем там остальные результаты смотреть или сразу возвращаем там результа?
37:53
Speaker A
Мы нет, мы возвращаем абсолютно любой результат, абсолютно все, точнее, результаты и одну ошибку склеенную из всех ошибок, которые мы встретили.
38:12
Speaker A
Так, сейчас проверю ещё раз всё. Угу. Так так. Так ну вроде вроде Всё верно.
39:25
Speaker A
Так, давай я тоже сейчас более внимательно посмотрю. B group. Ну вроде бы всё хорошо. Единственное, как думаешь, на пятьдесят девятой строчке нужна ли это вообще проверка?
39:56
Speaker A
Вообще, смотри, давай так. Если мы создаём там любой любой тип данных, там как не если мы создаём там сущность структуры и какие данные в ней изначально лежат ещё до того, как мы им что-то присвоили.
40:15
Speaker A
Ну, по идее, нулевые значения будут в зависимости от типа поля. Типа, если это мессич, это будет пустая строка.
40:23
Speaker A
Ага. Ну, а теперь смотри, вообще чисто в теории там же может быть кейс, что нам просто ничего не пришло, но при этом и ошибки не было.
40:34
Speaker A
Мм, [фыркает] да. Но у нас тут типа на двадцать седьмой строке всегда спринт вызывается.
40:44
Speaker A
Не, ну я понимаю, [смех] ты молодец, как бы, что заметил это. Всё верно. Но вот давай вот в случае, если бы это был каким каким-то синтетическим примером, это, я думаю, привело бы к ошибке. Давай-ка давай мы сейчас немножко подумаем, как вот исправить эту
41:03
Speaker A
ошибку. Типа, типа, мы всегда можем пушить результат. Типа смысла нет проверки ты имеешь в виду?
41:18
Speaker A
Да. Да. Хорошо. Смотри, а теперь даже если там возникла какая-то ошибка, то мы при любом раскладе запушим туда там нерелевантный ответ, правильно?
41:30
Speaker A
М. Угу. Ну, по идее, да, типа можно изменить тут, например, если ошибка, то мы не пушим в результаты ничего. Типа тут ставим [фыркает] continue.
41:48
Speaker A
Угу. Всё, вот теперь теперь всё вроде. То есть, если у нас возникла ошибка, то в таком случае мы её джойним continuum. А дальше нам уже неважно, что вообще вернулось там с какого-то урла.
42:06
Speaker A
Пусть засовываем его в пент. Так, ну, по этой задаче у меня вопросов нет. Я не знаю, Илья, может быть, хочешь что-нибудь спросить?
42:18
Speaker A
Да. В чём отличие erorр is и as? М. Итак, Ерес у нас проверяет, что ошибка, э, равна какой-то другой ошибке. Ну, не равна, а содержит в себе какую-то другую ошибку, которую мы передаём там вторым, по-моему аргументом.
42:41
Speaker A
А, короче, она нужно, чтобы там не точным равенством сравнивать, а, проверить всю там вложенность, потому что можем там через f как-то обернуть нашу ошибку. Если через равенството сравнивать, мы, так скажем, может получить неточный результат, не тот, который хотим.Рас
43:02
Speaker A
он у нас принимает, по-моему, указатель на какое-то значение. И если если мм ошибка содержит ошибка содержит.
43:34
Speaker A
Если ошибка содержит какую-то другую ошибку, по-моему, он что-то в этот указатель запишет. У меня вопросов нет.
43:52
Speaker A
Так, тогда я думаю, да, давай перейдём к следующему блоку. Вообще, как у тебя с СQэлем? Как часто работаешь с ним?
44:02
Speaker A
Угу. В принципе, часто мм ну, в принципе, достаточно хорошо уверенно. А, хорошо, давай тогда такие контрольненькие вопросы. Что такое индекс? Зачем он вообще нужен и какие виды бывают?
44:21
Speaker A
Угу. Так, ну, индекс - это у нас такая структура данных в СБДшках, которая позволяет оптимизировать какие-то запросы, а но при этом увеличивает размер, который нужно хранить, потому что индекс - это отдельная структура, и её нужно обновлять. Ну и плюс из-за
44:45
Speaker A
того, что её нужно постоянно держать, так скажем, в актуальном состоянии, это увеличивает там накладные расходы на запись и изменения строк. По типам индекса у нас, ну, в пост гогре дефолтный - это B3. Также есть шнкс, есть джинст Брин.
45:09
Speaker A
Мм, ну как-то так. Хорошо. Допустим, по поводу простой составной. Вообще в чём отличие между простым и составным?
45:20
Speaker A
Так, ну, составной у нас включает в себя несколько колонок сразу. А, то есть, если брать B3, то у нас там будет м сортировка сначала по первой колонке, которую мы включили. Потом внутри одинаковых первых колонок будет сортировка по второй колонке.
45:42
Speaker A
То есть тут нужно ещё учитывать, что если мы не будем использовать первую часть индекса, то есть левую часть индекса, то индекс может не работать.
45:53
Speaker A
О'кей. А порядок вообще полей в запросе, он как-то влияет на м использование индекса, по-моему, там новые версии постгре это, так скажем, делает под капотом, оптимизирует, что если у нас порядок там м, например, порядок полей из индекса не совпадает в порядке нашего запроса, то
46:20
Speaker A
он там, так скажем, приведёт к нормально оптимальному порядку. Блин, я я что-то даже, наверное, пропустил. Это надо будет посмотреть.
46:31
Speaker A
Так-то в Пасгре прикольные штуки. Я не знаю, я просто полагет MySQэля, хоть компании MySQL пользуется. Вот. А я не знаю, слушай, а с MyQL вообще работал когда-нибудь?
46:42
Speaker A
М. Да, не, не работал. Вот так вот, да? Не уважают, не уважаю. [смех] Ладно. Так, ладно, хорошо.
46:55
Speaker A
Небольшая лирическое отступление. Давай, слышал что-нибудь про покрывающий индекс? Вообще чем он нужен? Покрывающий, когда у нас типа все колонки, которые нужны запросу, задействованы внутри индекса. Там, например, через include мы можем добавить в постгре какие-то колонки, которые будут храниться вместе с
47:17
Speaker A
индексом. И там не нужно будет субдшки, э, из индекса IT читать там страниц таблицы, строки, то есть делать там, по-моему HIPФЧ он сразу возьмёт все нужные колонки для запроса из индекса, ну, и вернёт результат.
47:37
Speaker A
О'кей. А вот про кластерный индекс вообще слышал что-нибудь? Кластерный индекс какое-то другое название есть, а то что-то вообще не слышал такое.
47:51
Speaker A
Блин, кластер. Слушай, я не знаю. Ну я вот в литературе встречал только там кластеры индекс. Кластерный индекс по-русски.
48:00
Speaker A
А может ты имеешь в виду частичный индекс, типа, когда мы только на часть данных через вешаем?
48:07
Speaker A
Не, не, нет, нет, нет. Ладно, чуть-чуть не то. Э, короче, это индекс, благодаря которому вся таблица у нас лежит. Ну, в общем, изначально это как как бы когда ты индекс строишь, у тебя, грубо говоря, но твоего дерева, там B3 или и так
48:30
Speaker A
далее, она там ссылается на указатель, в который лежит м там типа остальные данные, скажем так, от от вот этой записи. Вот. Аэ, в кластерном индексе у тебя получается вся таблица лежит внутри этого индекса, и ему вообще ни с чем не
48:44
Speaker A
надо, никуда не нужно ходить. Вот. Э, ладно, давай, э, сейчас такие небольшие практические SQL-селектики попишем.
48:55
Speaker A
Так, чисто для разогревочки. В общем, смотри, есть такая прямо ультрапростенькая система БДшек. Сейчас. Что у нас тут? А, сейчас я посмотрю, где тут SQL.
49:08
Speaker A
чтобы синтексис подсвечивал. В общем, есть две таблицы: usеer и продукт. US - это таблица админов.
49:18
Speaker A
User ID - это тот, кто, грубо говоря, создал этот продукт. - это цена продукта. Type, name - это название. Create - это то, когда сделали. Ну, и у админа только два поля. Это ID и email.
49:36
Speaker A
Давай начнём первую задачку. Вывести срочно всех пользователей. Угу. Н посто Так у всех пользователей все продукты, которые он завёл.
50:05
Speaker A
Type name. Так, я не буду название схемы писать. О'кей. Да, без проблем. Что? Так, ну, вроде так.
51:04
Speaker A
А можешь, пожалуйста, отсортировать их по User ID? М. Так. Select ID mail join product on.
51:27
Speaker A
В на семнадцатой строчке ты использовал. Какие вообще виды джоинов знаешь? Угу. И примеры их использования.
51:37
Speaker A
Угу. Так, ну по дефолту сейчас используется у нас inner joint, то есть когда у нас возвращаются только те строки, для которых нашлось совпадение в обеих таблицах.
51:50
Speaker A
Есть ещё left, right, joint. Left - это когда у нас все строки из левой таблицы и совпавшие строки из правой возвращаются.
52:02
Speaker A
Если правая часть в правой таблице не нашлось совпадения, то там будет м правые колонки заполнены нулами. Ну и для й джойна примерно то же самое.
52:16
Speaker A
Есть ещё там self self joint, по-моему, типа это когда мы как-то само собой что ли соединяем таблицу. Есть ещё ещё есть декартового произведения, да?
52:36
Speaker A
Это когда у нас, по-моему, каждая таблица, точнее каждая строка из левой таблицы соотносится с каждой строкой из правой таблицы. Угу.
52:49
Speaker A
О'кей. Ладно, тут понял. А давай так. Смотри, если бы мы здесь вместо обычного джойна написали left join, как бы примерно выглядело то, что нам вернётся.
53:02
Speaker A
Угу. Такти. Так, если бы написали left, то вернулись бы все пользователи, у которых даже нету этих м никаких продуктов, но их правая часть там была заполнена [вздыхает] этими, ну, нулами, как я сказал. Короче, вернулись бы все пользователи, даже если
53:30
Speaker A
у них нет продуктов. О'кей, хорошо, я понял. Так, давай тогда перейдём к следующей задачке.
53:39
Speaker A
Давай выведем три админаче заведённых продуктов за январь двадцать пятого года и предварительно отсортировать их по общему амаунту продуктов, которого они звили.
55:11
Speaker A
Блин, что-то забыл, как достать год из Create Day Time. Там, по-моему, есть экстракт через него. Ну, э да, если что-то не знаешь, я думаю, там нам важно понимать, что, типа, ты не идеально знаешь там синтаксис с там как работать с Дйтаймом
55:36
Speaker A
или там с Джейсоном, JС B полем и так далее. Вот. Поэтому, если что, ты можешь просто здесь написать там условный экстракт ээ там и о'кей. Важно просто понимать, что ты вот умеешь пользоваться там СQэлем, знаешь какие там нюансы его работы, но
55:57
Speaker A
не идеально знаешь синтаксис. Давай вот так. Угу. 2025 Давай в порядке убывания. Так, порядок убывания. Этодинг, да?
57:05
Speaker A
Угу. Давай чуть-чуть повнимательнее прочти, пожалуйста, условия задачи. Так, вывести топ-три админав за январь. А, по количеству заведённых продуктов.
57:34
Speaker A
Топ три по количеству заведённых продуктов. Так, по идее тогда м по идее тогда ещё нужна у нас сортировка по количеству и из них уже брать топ-три.
57:52
Speaker A
Угу. Найти три. А что тебе выведет countдуct ID? Если ты возьмёшь просто counto productт количество всех продуктов в таблице по идее походу нужна группировка ещё группировка по user idil Так, по идее, сейчас должен каунт вывести количество продуктов только для определённого юзера.
59:15
Speaker A
А что ты здесь, смотри, что ты здесь группируешь? Так группирую. Ну, по идее, группируй пользователей.
59:37
Speaker A
А тебе, чтобы найти количество заведённых продуктов пользователем, тебе вообще по какой таблице, скажем так, группировать надо?
59:49
Speaker A
Как думаешь? Ну, смотри, нам же нужно выяснить, какое количество продуктов завёл пользователь. А, а какие продукты вообще где, в какой таблице у нас хранятся вообще эти продукты, которые завёл пользователь?
60:03
Speaker A
Угу. Ну, понятно, что в продуктах. Вот. Да. И, соответственно, как вообще у нас связываются usер и продукт, таблица продукт.
60:14
Speaker A
Ну, по usейдишнику. Вот, соответственно, ну, чтобы понять, что вот там пользователь А завёл там 30 продуктов, а пользователь Б завёл 50 продуктов.
60:27
Speaker A
Как думаешь, мы должны что сделать? Сгруппировать по user дишник, да, в таблице, соответственно, продукт. Вот.
60:43
Speaker A
Угу. То есть, соответственно, в Groupy нам нужно поменять user.id user.email на А что? Да, совершенно верно.
61:06
Speaker A
Таким образом сможем использовать user ID, user email. Нет, ну давай. Ну подожди, а там у тебя изначально разве написано был user email?
61:21
Speaker A
Ну да. ID email. Да. Да. Почему сможем? М по идее же мы можем использовать только те ключи. А, хотя, стоп, мы же группируем по таблице этих.
61:40
Speaker A
Да, мы можем мы можем грубай делать только там, где мы то, что мы используем.
61:51
Speaker A
Так [откашливается] order by count id desk. Он, смотри, мы можем growY делать только по тому полю, которой используется изначально, ну, в этом в селекте.
62:07
Speaker A
Соответственно, нам нужно будет добавить просто usеer ID выше в селект сам, чтобы вывести его, да?
62:23
Speaker A
Так. Order by count deskunt product desk prodct о'кей вроде всё норм. Я не знаю, Илья, есть ещё какие-то вопросы по этой задаче?
62:47
Speaker A
Нет. Давай небольшой небольшой вопросик. Я не знаю, видел когда-нибудь вот подобную запись в лимите?
62:57
Speaker A
Если мы там в лимите пишем сейчас, давай, наверное, чтобы не портить твою твоё решение. Вот такой лимит когда-нибудь видел?
63:07
Speaker A
М, не видел. Может, это типа, чтобы осет не сдавать, не знаю. Ну да, всё совершенно верно. Да, на самом деле это просто краткая запись.
63:18
Speaker A
Лимит, офсеset 10. Э в целом, какие подводные камни при использовании лимиты осе, не знаю, может быть, натыкался хоть раз на эти грабли или слышал про них?
63:33
Speaker A
М Угу. Слышал, что, например, в каких-то системах, где у нас много строк в таблице, желательно это не использовать.
63:45
Speaker A
Ну, из-за того, что это будет, скорее всего, как-то не оптимально, там придётся читать много строк или что-то такое сбдшки и там использовать какие-нибудь другие виды погинаций типа курсорных.
64:01
Speaker A
Угу, совершенно верно. Э, хорошо. Кроме курсорной, помнишь ещё какую-нибудь? Угу. Я не помню. О'кей, хорошо. Тут без проблем. Давай попробуем на примере таблицы product. Попробуем курс based просто вот так.
64:39
Speaker A
Угу. Максимально не запариваясь. Так, это надо написать какой-то новый запрос, да? Да, просто обычный селект на основании, ну вот давай так вот тебе доверили задание там на таблицу продукт сделать там погинацию для опишки. Ну, соответственно, тебе нужно как бы
65:02
Speaker A
составить запрос. Давай посмотрим, какой вообще можно запрос составить, чтобы мы там на страницу там состоящую из двадцати продуктов делали погинацию. Вот так.
65:19
Speaker A
Угу. Так. Так. Так. Курсор - это когда мы по какому-то айдишнику обычно Угу. проходимся. Короче, от айдишника зависит количество страниц.
65:51
Speaker A
Как только у нас продукта адишника нет. Ну так это использовать. Да, всё верно. Мы на самом деле можем использовать любое уникальное значение, не только айдишник.
66:11
Speaker A
Ну там Warcraft там больше какого-нибудь другого крейта. А чисто ради интереса, почему доллар? М просто обычно там плейсхолдеры кому-нибудь по Джейксе, это доллар.
66:29
Speaker A
А, а в целом, может быть, знаешь, как, э, параметры задаются в СQэле и через доллары.
66:39
Speaker A
Ну нет, я поэтому я бы в таком случае не спрашивал. Ну так, да, не что-то не по А никогда не заду, ну там вот как это CSS инъекциями не видел прямо стандартные примеры, как бы вот SQL инъекции.
67:01
Speaker A
Да-дада. SQL икци. М, ну, в принципе, видел там типа когда какой-нибудь Sprint F использует, чтобы эти инжектить параметры внутрь SQL запрос.
67:17
Speaker A
Ну ладно, я тут Ну всё, я я тебя мучить не буду, на самом деле. Можно просто там через двоеточие в СQLле это всё происходит.
67:23
Speaker A
Угу. Ээ так. Ах, звёздочка from product. Слушай, вот ещё буквально там пара слов, которые 100% помогли бы нам никогда не закосячивать в целом спагинации. Как думаешь, какие могут быть?
67:46
Speaker A
Угу. Так вот тут запрос полностью правильный, и скорее всего он там всегда будет отдавать одно и то же, но при этом вот как можно ещё макси, ну ещё более себя обезопасить, чтобы мы точно не закосячили. Ну давай так. На основании чего вообще в целом мы
68:06
Speaker A
ээ доверяем курсор base? Мне за счёт может ты имеешь в виду там отсортировать криate этот вот. Да, да, да, всё верно, да. То есть нам нужно, чтобы они всегда возвращались в одном и том же порядке.
68:23
Speaker A
Соответственно, что нам нужно в этот запрос? Угу. Ну, order by create и там какой-нибудь или AS или das в зависимости от бизнес-логики.
68:33
Speaker A
Да, всё верно. Вот тут иногда забывают и не всегда, но это иногда может произойти какая-нибудь ошибка.
68:45
Speaker A
Так, Саш, я тебя поздравляю. Э, у меня вопросы закончились. Ээ, если давай я, наверное, расскажу сейчас про сво про команду и отвечу на вопросы, которые возникли у тебя.
69:04
Speaker A
Так [вздыхает] так. А говоришь MySQL используйте, да? Не, нет, нет, нет, нет. Это я просто апологет MySQL. Не знаю, просто очень нравится. Мне как-то вот с универа так пошло, что очень мне нравится. Поэтому во всех э-э этих пэпроектах используем
69:23
Speaker A
SQL как-то спасгр у меня. А так у меня у нас стандарт компании абсолютно все и пользуются, ну как, абсолютно все проекты ходят в постгре SQL.
69:33
Speaker A
Угу. А чем говоришь отличается My SQL от Постгриз? Слушай, там прикольно, что есть всякие разные движки, и там в зависимости от какой-то определённой задачи воще чуть ли не как мемкаш можно использовать.
69:50
Speaker A
Там есть такая штука. Через пару дней мне дали положительный фидбэк по этому сабесу, но, к сожалению, вакансию поставили на холд.
Topics:Golangсобеседованиефинтехmiddle разработчикGo слайсыGo мапымногопоточностьSQL запросыкластерный индексменторство

Frequently Asked Questions

Почему в Go слайсы передаются по значению, но изменения внутри функции видны снаружи?

Слайс в Go — это структура, содержащая указатель на базовый массив, длину и емкость. При передаче слайса в функцию копируется структура, но указатель остаётся на тот же массив, поэтому изменения элементов массива видны и снаружи.

Почему не рекомендуется использовать float32 в качестве ключей мап и для хранения денежных значений?

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

Как в Go обеспечивается синхронизация при работе с многопоточностью?

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

Get More with the Söz AI App

Transcribe recordings, audio files, and YouTube videos — with AI summaries, speaker detection, and unlimited transcriptions.

Or transcribe another YouTube video here →