Использование таблицы исключительно в качестве индекса для облегчения поиска

#database-design

#база данных-проектирование

Вопрос:

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

Я пишу на Java и использую MySQL в качестве базы данных.

Пример проблемы, с которой я столкнулся, описан ниже.

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

Таким образом, только с точки зрения начальных карточек, возможно, хранится 20 миллионов значений. Мне нужно будет сделать такие вещи, как:

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

Я думаю, что правильный способ сделать это заключается в следующем:

  1. У меня будет таблица (таблица A), в которой хранятся сведения об игроках в игре. По одной строке на игрока за раздачу.
  2. Чтобы определить две закрытые карты для данного игрока, у меня будет отношение «один ко многим» от таблицы A к таблице (таблица B), которое структурировано следующим образом:
    • Внесите индекс внешнего ключа в таблицу A, чтобы определить строку, соответствующую данной раздаче и игроку
    • Имейте две строки в таблице B для каждой строки в таблице A, по одной для каждой закрытой карты.
    • Таким образом, я могу выполнить поиск в таблице B для карт, которые я ищу, а затем использовать взаимосвязь, чтобы найти игроков и игры, в которых появились карты.

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

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

Есть ли какие-либо недостатки в моем подходе?

Ответ №1:

enum Здесь может показаться очень уместным — данные в основном никогда не меняются, если вы также не собираетесь играть в Таро (имеет Кавалера между J и Q) или Рамми (добавляет 2-3 джокера на колоду).

Тем не менее, для карточек я бы лично придерживался int, потому что вы можете использовать его для введения сортировки и магии where-condition. Например, если у вас есть:

 51 - AS
50 - AH
49 - AD
48 - AC
47 - KS
...
01 - 2D
00 - 2C
  

Тогда можно с уверенностью сказать, что (i mod 4) это дает масть карты (3 = S, 2 = H и т.д.) И, следовательно, ранг масти, и это i - (i mod 4) связано с номером карты и, следовательно, с рангом карты. Несколько объединений и (возможно, функциональных) индексов позволят вам извлекать статистику в кратчайшие сроки.

Суть здесь в том, что внутренне перечисление — это то же самое, что иметь таблицу из 52 строк; просто: а) вы не видите фактических значений чисел, б) они предварительно оцениваются внутренне перед выполнением реальных запросов (что вам в любом случае следует делать) и в) вы не можете ввести магию нумерации, которая в противном случае могла бы быть полезна для карточных игр.

Комментарии:

1. Большое спасибо за мысли о хранении карточек. Вот несколько полезных идей. Моя главная забота заключается в структурировании базы данных, чтобы я мог выполнять запросы большого объема, и есть ли какая-либо причина, по которой я хотел бы хранить их ненормализованным способом (card1, card2 в строке таблицы. Я думаю, что, судя по вашему ответу, вы предполагаете, что я буду хранить карточки в полностью нормализованной структуре, чтобы я мог выполнять «правильные» запросы. Если вы можете уточнить это, я был бы признателен.

2. После прочтения вашего вопроса у меня сложилось впечатление, что у вас была или планировалась какая-то таблица (card_id, card), строки которой были по существу неизменяемыми и (правильно) задавались вопросом, можно ли их заменить перечислением. Я бы ответил, что да, это возможно, но вам было бы еще лучше изучить идею представления карточек в виде целого числа.

3. Я думаю, что останусь при своем предложении. Похоже, что A и B могут быть объединены в любом случае…

4. Хорошо, спасибо, что нашли время помочь. Я признаю, что я немного удивлен, что вы считаете, что A и B должны быть объединены, поскольку это подразумевает нарушение нормализации и обрекает меня на более сложные запросы для проверки обоих полей карточки. Приветствовались бы некоторые мысли о том, почему вы считаете, что это правильный путь.

5. Ну, дело в том, что я в основном помешан на Postgres. И PG позволяет создавать индексы при вызовах функций. С двумя полями int, представляющими две карты, вы могли бы произвести индексацию (card mod 4) для масти и необходимой формулы, которая выдает ранг карты. Вы также можете создавать частичные индексы, например, индексные комбинации с парами или комбинации с одним или несколькими тузами и т.д. И в конечном итоге вы будете вести всю свою статистику в одной, тщательно построенной таблице.

Ответ №2:

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

Это была бы обобщенная структура, которая позволяла бы хранить любое количество начальных карт или даже состояние по ходу игры при раздаче новых карт!

Вам просто нужно решить, например, ваша 54-разрядная структура будет ‘1000100000….(много битов) ….0000’ если у игрока были туз треф и 5 треф, то вы могли бы использовать растровые изображения для выбора строк из базы данных, которые соответствуют вашим критериям. Если бы вы сделали какую-нибудь умную группировку мастей, то могли бы получить несколько очень быстрых анализов!

Битовая структура особенно важна, если возникает проблема с пространством.

Звучит как забавный проект!

Комментарии:

1. Спасибо за этот ответ. Это не помогло мне с моей проблемой с базой данных, но ваши мысли о хранении карточек (и мысли Дениса тоже) заставили меня задуматься, поскольку я думаю, что, вероятно, смогу улучшить свой текущий подход. Еще раз спасибо.