LINUX.ORG.RU

Базы данных. Несколько вопросов для общего понимания

 


0

1

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

Итак, есть таблица продаж с полями : saleId, productId, customerId, date

Теперь вопросы касающиеся РЕАЛЬНОЙ (как по идее устроено у тех же интернет магазинов) базы данных:

1) Таблица отсортирована по дате продаж? Понятно, что для различных запросов к базе могут понадобиться разные сортировки и нет смысла хранить ее в какой-то одной. Но покупки же физически проходят последовательно во времени. Их записывают в том же порядке последовательно или все распараллелено и элементы таблицы в итоге записываются в совершенно хаотичном порядке?

2)В системе хранится где-то в явном виде размер таблицы (переменная), инкрементируясь при каждой покупке, или его можно получить только пройдясь по таблице?

3)Как выбираются идентификаторы (Id)? Последовательно или случайно? Начиная с 0 или совершенно с любого числа? Верно ли предположение, что если пройдясь по таблице мы нашли минимальный идентификатор клиента (customerId) равным MIN и максимальный равным MAX, то число MAX - MIN даст число разегистрированных покупателей?

1) Нет. Может быть индекс по дате продаж, если ты его заведешь, он ускорит запросы с сортировкой. 2) Нет. Запросом или ты сам навелосипедишь триггерами, например. 3) В разных по разному, есть поля типа автоинкремент, есть генераторы, можно просто вычислять перед вставкой. Число покупателей только запросом.

ilovewindows ★★★★★
()
Последнее исправление: ilovewindows (всего исправлений: 2)

1. Данные никак не «сортируется» для сортировки по дате, надо строить индекс для этого. Для выборке по дате без индекса придется перебирать по всем строкам таблицы. 2. Разные базы данных по-разному оптимизируют создание первичного ключа. Все еще зависит от того, что выступает в роли ключа. 3. Смотря что ты используешь для первичного клюяа.

nikolnik ★★★
()

Все твои вопросы зависят от СУБД. Далее как это обычно бывает в реляционных....

... и элементы таблицы в итоге записываются в совершенно хаотичном порядке?

Никак не сортируются, но по факту будут распологаться примерно в хронологическом порядке если из таблицы ничего не удаляется.

...или его можно получить только пройдясь по таблице?

Точное значение только через обход или какие-либо ручные хаки на триггерах. Сами СУБД могут периодически анализировать содержимое таблиц и считать оценочные статистические данные для оптимизатора, в этих статистиках будет примерная оценка объёма.

Последовательно или случайно?

Как-то упорядочнено, обычно от 0 вверх.

Верно ли ... число MAX - MIN даст число разегистрированных покупателей?

Нет.

mashina ★★★★★
()

MAX - MIN + 1

anonymous
()

Число клиентов запросом... то есть будет перелопачиваться вся таблица в поиске всех уникальных Id клиентов? Или есть какие-то хитрые способы? А не может быть отдельно хранящегося массива зарегестрированных клиентов? Или это тогда уже считается объектно-ориентированной базой данных?

Тогда еще вопрос: абсолютно нормальна ситуация, когда при обработке какого-то запроса может выделяться массив с длинной, равной длинне основной таблицы (не столько же весить, а иметь ту же длинну для отображения)? Или память используют по минимуму и предпочтут лишние проходы по основной таблице?

Zhenek91
() автор топика

В mysql:
1. Так, но хз, что там может произойти. Лучше использовать индексы.
2. Да, в индексе хранится count(*)
3.1. Если задан автоинкремент, то последовательно начиная с единицы. 3.2. Верно, но это ужасный костыль, лучше сделать отдельную таблицу с покупателями.

crutch_master ★★★★★
()
Ответ на: комментарий от Zhenek91

Число клиентов запросом...

Если поле проиндексировано, то min и max можно взять из индекса. Но это плохой, не годный подход. При удалении одной единственной записи все полетит псу под хвост.

когда при обработке какого-то запроса может выделяться массив с длинной, равной длинне основной таблицы

Будет очень тормозно, если в переменную, например, выбрать все id, а потом их засунуть в какой-нибудь другой запрос. Есть способы проще. Пиши пример, что хочешь сделать.

crutch_master ★★★★★
()

Таблица отсортирована по дате продаж?

совершенно не обязательно. но чтоб крутить ее и так и эдак тебе свыше дадены индексы.

В системе хранится где-то в явном виде размер таблицы

для этого есть count (1)

Как выбираются идентификаторы (Id)? Последовательно или случайно?

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

пройдясь по таблице мы нашли минимальный идентификатор клиента (customerId) равным MIN и максимальный равным MAX, то число MAX - MIN даст число разегистрированных покупателей?

совершенно не обязательно. если у тебя ID --- UUID, то такая математика не получается.

но count тебя спасет.

Rastafarra ★★★★
()
Последнее исправление: Rastafarra (всего исправлений: 1)
Ответ на: комментарий от Zhenek91

Хитрый способ повесить на основную таблицу триггеры на вставку, обновление и удаление записи. В триггере обновлять данные в таблице, которую ты пытаешься назвать «массивом зарегестрированных клиентов». Она меньше по количеству полей, возможно будет работать быстрее, но получишь два продублированных источника данных, твой организм должен на такие ситуации возмутиться на уровне подсознания. Рано или поздно такие оптимизации заканчиваются рассинхроном и ты проклянешь все на свете пока найдешь ошибку. Заведи индекс на ИД клиента, будет нормально быстро работать.

С базой на уровне API уже не работает никто, работают на уровне прокладки, которая делает примерно следующее - формирует запрос, где-то в недрах хранит его ИД, выдает первые сколько-то записей, если ты будешь считывать больше записей, то последуют другие запросы к API сервера, который достанет по ИД запроса следующую порцию записей. При повторном обращении какое-то время может работать кэш на сервере. Короче, кухня сложная и зависит от БД, ничего самодельными велосипедами не выиграть, там уже ползали несколько поколений программеров.

ilovewindows ★★★★★
()

1) Таблица отсортирована по дате продаж? Понятно, что для различных запросов к базе могут понадобиться разные сортировки и нет смысла хранить ее в какой-то одной. Но покупки же физически проходят последовательно во времени. Их записывают в том же порядке последовательно или все распараллелено и элементы таблицы в итоге записываются в совершенно хаотичном порядке?

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

3)Как выбираются идентификаторы (Id)? Последовательно или случайно? Начиная с 0 или совершенно с любого числа?

В идеале идентификаторы, хотя скорее речь о первичных ключах, должны быть естественными, но почти везде используются суррогатные ключи, вроде счётчика, UUID и прочего. Единственная задача у них - быть уникальными в пределах таблицы (или отношения).

Верно ли предположение, что если пройдясь по таблице мы нашли минимальный идентификатор клиента (customerId) равным MIN и максимальный равным MAX, то число MAX - MIN даст число зарегистрированных покупателей?

Даже если ключ реализован счётчиком, то удаление сломает всё.

WDWTFWW
()

Чётко раздели уровни

п. 3 - нет, неверно, используй SELECT COUNT().

п. 2. Используй SELECT COUNT().

п. 1. Если ты выводишь значения таблицы без сортировки - ты должен предполагать, что порядок вывода записей будет определяться исключительно настроением тёщи твоего однокурсника, поделённым по модулю фазы Луны. Если нужна сортировка - в таблице нужны соответствующие поля, в запросе у тебя должен быть явно написан ORDER BY, а чтобы эта сортировка была быстрой - в таблице должен быть соответствующий индексов. Индексов у таблицы может быть много, для разных запросов.

Вообще, все три твоих вопроса объединяет одно. Ты лезешь в слишком низкий уровень абстракции, который на прикладном уровне несёт только вред. Если ты собираешься писать запросы и хранимые процедуры - НЕ НАДО делать никаких предположений, как это реализовано внутри. Есть стандартные методы: индексы, функции. У сишников то, чем ты интересуешься, называется UB (undefined behaviour), и полагаться на его реализацию - признак непрофессионализма.

Вот если ты когда-нибудь будешь разрабатывать СУБД (править исходный код PostgreSQL, например) - да, там такие тонкости понадобятся. А тащить их на прикладной уровень нельзя.

anonymous
()
Ответ на: комментарий от crutch_master

Нужно каждому продукту поставить в соответствие число - сколько раз он был первой покупкой клиента.

На мой зеленый взгляд алгоритм: 1)получить с помощью индексов данные в хронологическом порядке 2)Идти индексами по основной таблице, делая следуещее: 2.1)Есть ли клиент во временном массиве клиентов? 2.1а)Нет - клиент совершает первую покупку. Добавить его во Временную таблицу, а также добавить купленный товар во временный массив товаров(если его еще там нет) и инкрементировать/установить равным 1 его счетчик. 2.1б)Да - клиент совершает не первую покупку, так что идем дальше

После полного прохода получится временный список пар : (товар, количество случаев, когда он - первая покупка клиента) Этот временный список товаров еще можно отсортировать по возрастанию/убыванию их счетчиков.

Обращаю внимание, что это не указано, чем это решать. Мне интересно для понимания выбрать классический язык программирования, типа С++.

Еще момент насчет «индексов свыше») Правильно ли я понимаю, что использовать индексы - сделать целочисленный массив с длинной, как у основной таблицы, а каждый его элемент - это индекс элемента основной таблицы, выбранный так, что проходя по основной таблице используя эти индексы - мы проходим по данным в порядке какой-то сортировки?

На грубый пример 3 покупки:

Id = 3; product Id = 27; customerId = 101; date = 10.12.16 0:00 Id = 1; product Id = 51; customerId = 87; date = 8.12.16 0:00 Id = 2; product Id = 16; customerId = 243; date = 9.12.16 0:00

тогда здесь «использовать индексы» для сортировки по дате - значит выделить массив array = {1, 2, 0} ?

Zhenek91
() автор топика
Ответ на: комментарий от Zhenek91

Простите за ломку глаз, предполагал, что все будет ровно с вертикальными отступами, поленился предпросмотр сделать(

Zhenek91
() автор топика
Ответ на: комментарий от Zhenek91

Обращаю внимание, что это не указано, чем это решать. Мне интересно для понимания выбрать классический язык программирования, типа С++.

Эмм... то есть задача сделать свою самопальную СУБД? Или всё же использовать одну из существующих? C++ вполне себе можно использовать на клиентской стороне, посылая к существующей СУБД SQL-запросы.

Если СУБД всё же используется готовая, то перечитай мой комментарий выше. На всё это имеются стандартные средства, не надо велосипедить никаких массивов.

anonymous
()

1. Нет. Я так уже однажды делал (там не дата продаж была, а дата поступления товара на склад), огрёб массу проблем.

Deleted
()
Ответ на: комментарий от Zhenek91

Да я догадываюсь, что на прикладном уровне БД используется SQL

Но если вакансия называется программист C++, а работодатель дает задачку на БД, ее решать на C++ или SQL?) При том, что в условиях о том, чем решать, ничего не сказано.

Zhenek91
() автор топика
Ответ на: комментарий от Zhenek91

Нужно каждому продукту поставить в соответствие число - сколько раз он был первой покупкой клиента.

Если речь идет о РСУБД с SQL, то такой алгоритм - то, как делать не стоит.

Всё это делается куда элегантней, ибо для подобных задач SQL и создан: таблица покупок группируется по покупателям и агрегируется минимальная дата -> результат соединяется с этой же таблицей, группируется по товару и агрегируется число строк -> таблица товар-число первых покупок.

WDWTFWW
()
Ответ на: комментарий от Zhenek91

На SQL ты её в любом случае будешь решать, только для тебя SQL будет строкой текста. Вопрос ты будешь пользоваться сторонними библиотеками или полезешь к API сервера. Спроси прямо чего от тебя хотят. Ненавижу вот эту клоунаду на собеседованиях с их идиотскими вопросами.

ilovewindows ★★★★★
()
Ответ на: комментарий от Zhenek91

Но если вакансия называется программист C++, а работодатель дает задачку на БД, ее решать на C++ или SQL?)

Так спроси у него.

Нужно каждому продукту поставить в соответствие число - сколько раз он был первой покупкой клиента.

Как-то так:

select productId,count(productId) from sales, 
   (select min(id) as id 
      from sales 
      group by customerId) as a 
where sales.id = a.id 
group by productId
На субд можно делать почти любые манипуляции.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от Zhenek91

если вакансия называется программист C++, а работодатель дает задачку на БД, ее решать на C++ или SQL

Втыкаете в свою программу на C++ библиотеку SQLite и решаете на обоих языках.

anonymous
()
Ответ на: комментарий от crutch_master

Судя по скорости его вызова, где-то там он есть.

Мало ли что тебе кажется по ощущениям, с индексом может быть быстрее если он занимает меньше места чем сама таблица. рСУБД будет вычитывать либо всю таблицу, либо весь индекс, скорость выполнения примерно будет зависеть от объёма в байтах.

mashina ★★★★★
()

Таблица отсортирована по дате продаж?

А какая у тебя база данных? Реляционная? Тогда нет, хотя можно вводить в некоторых реализациях индекс для ускорения поиска.

Их записывают в том же порядке последовательно или все распараллелено и элементы таблицы в итоге записываются в совершенно хаотичном порядке?

Всё зависит от реализации. В общем (да и в подавляющем большинстве случаев) случае доверять подобным идеям нельзя.

В системе хранится где-то в явном виде размер таблицы (переменная), инкрементируясь при каждой покупке, или его можно получить только пройдясь по таблице?

Зависит от реализации. Но доступ к такой переменной ты не получишь, даже если она и есть где-то в недрах СУБД.

Как выбираются идентификаторы (Id)?

Ты сам их выбираешь.

Последовательно или случайно?

Как захочешь/зависит от реализации

Начиная с 0 или совершенно с любого числа?

Зависит от реализации, хоть в обратном порядке.

Верно ли предположение, что если пройдясь по таблице мы нашли минимальный идентификатор клиента (customerId) равным MIN и максимальный равным MAX, то число MAX - MIN даст число разегистрированных покупателей?

Не верно. Ты забываешь про удаление/добавление новых клиентов + реализация может давать там рандом.

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от crutch_master

Да вряд ли, count имеет смысл внутри текущей транзакции, для каждой он свой. Слишком накладная кухня получается, не так уж и нужен этот count.

ilovewindows ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.