Модераторы: skyboy
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Использование CHAR в качестве PRIMARY, Стоит или не стоит? 
V
    Опции темы
fridkaratel
  Дата 25.11.2012, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Задался вопросом - использование CHAR в качестве ключа PRIMARY...

Создал тестовую таблицу на 100 000 строк - разницы на локальном сервере не заметил.
То есть, что выборка по INT (11), что выборка по CHAR (12) - дала одинаковые результаты.

Хотелось бы узнать, какие есть последствия использования CHAR в качестве ключа?

---------------------

Вот пример, где легче работать с CHAR чем с INT.

Есть пользователи, есть товары и есть заказанные пользователем товары.
Пользователь хочет изменить количество с 10 на 20.

При работе с INT необходимо выбрать все товары, заказанные пользователем, чтобы узнать OrderCommodityId в базе.
При работе с CHAR нет необходимости выбирать все товары - OrderCommodityId будет всегда UserId + '_' + CommodityId.

То есть, при CHAR в качестве PRIMARY KEY не надо делать выборку - а просто одним запросом INSERT ON DUPLICATE KEY UPDATE.

---------------------

Посчитаем...
Пользователей: 1 000 000
Товаров: 100 000
Получается, что длина макс. OrderCommodityId будет 1000000_100000 - это 15 знаков.

---------------------

Выборка по Id будет всегда происходить при условии 100% равенства, т.е. не будет LIKE и т.п.

---------------------

Также вижу, что в таком случае нет необходимости удалять значения из БД.
Например, пользователь заказал товар.
В таблицу добавилась строка с OrderCommodityId=100_999 и количеством.
Потом пользователю выдали товар, и количество изменили на 0.
В таких случаях, таблица не будет фрагментироваться...

---------------------

Если в обработке задействованы, например, 3 таблицы, то опять же надо делать выборку из этих двух таблиц, чтобы получить Id элемента в каждой из них.
В случае с CHAR мы через PHP-скрипт генерируем его Id, разделяя нижним слешем, и всё.
А потом INSERT ON DUPLICATE KEY UPDATE...

---------------------

Что скажете по всему этому?
Очень хочется узнать вашего мнения, а также за и против...
PM   Вверх
lomaster
Дата 25.11.2012, 09:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 101
Регистрация: 27.5.2012

Репутация: нет
Всего: 2



Цитата

Что скажете по всему этому?
 Ерунда какая-то.
Вы лучше почитайте про реляционные базы.
Тогда лайки, фрагментации и т.п. в голову лезть небудут.
PM   Вверх
fridkaratel
Дата 25.11.2012, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Да, но...

Например, есть товар: ItemId=123 и Sku=SK91 (Sku - это артикул).
Есть несколько складов, где есть этот товар.
При выдаче товара я выбираю склад, откуда его выдать.

В итоге, мне нет необходимости его искать через SELECT.
Достаточно составить ключ из ID склада и ID товара - и всё.
А далее через INSERT UPDATE обновить количество на складе.

Что выдать 1 товар, что выдать 100 товаров - не надо их выбирать через SELECT WHERE IN (...).
Мне вообще не надо знать ID для этого товара на складе.
Я его генерирую через PHP и тем же INSERT UPDATE обновляю.

Как-то вот так... smile

Мне кажется, это удобно и... понятней, нежели выбирать ID...

Но я сомневаюсь в таком решении, потому как не специалист в области БД, поэтому и попросил советов и рекомендаций... ;-)
PM   Вверх
skyboy
Дата 25.11.2012, 14:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 41
Всего: 260



Цитата(fridkaratel @  25.11.2012,  07:51 Найти цитируемый пост)
То есть, при CHAR в качестве PRIMARY KEY не надо делать выборку - а просто одним запросом INSERT ON DUPLICATE KEY UPDATE.

а что тебе мешает это сделать при составном первичном ключе на двух полях — userID и commodityID?
тем более, что "вывести все заказы данного пользователя" — тоже потенциально не редкий запрос, в случае составного ключа. а вот в случае строкового ключа — все сложнее. особенно, если у тебя в значениях "1_1245" и "10001_5640" часть под userID имеют разную длину — тогда и оптимизация не поможет, будет так же быстро, как Like "10001_%"
PM MAIL   Вверх
lomaster
Дата 25.11.2012, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 101
Регистрация: 27.5.2012

Репутация: нет
Всего: 2



Здается мне что у автора склад неправильно сделан, вот и ищет как правильно, но не в той степи.
PM   Вверх
fridkaratel
Дата 26.11.2012, 02:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



@skyboy:
Цитата
значениях "1_1245" и "10001_5640" часть под userID имеют разную длину — тогда и оптимизация не поможет, будет так же быстро, как Like "10001_%" 

В таблице будет столбец с Id пользователя...
И с Id товара...
То есть примерно так:
- StoreCommId = CHAR (12)
- StoreId
- CommId
- StoreQty

Если StoreCommId - это INT (11) с автоувеличением, то в случае обновления более одного товара на складе придётся:
А) Или сразу выбрать CommId всех товаров, а потом делать INSERT ON DUPLICATE UPDATE
Б) Обновлять без проверки дубликатов, а через WHERE StoreId=A AND CommId=B

В случае же использования CHAR в качестве PK отпадёт выборка товаров со склада
Мне надо будет в PHP-скрипте сгенерировать StoreCommId из тех значений, которые мне уже известны - StoreId и CommId...

Как то так... ;)

-------------

@lomaster
Здается мне что у автора склад неправильно сделан, вот и ищет как правильно, но не в той степи. 
Я не являюсь специалистом базах данных, потому не могу точно сказать о правильности своего выбора.
Но я стараюсь, учусь smile Читаю и изучаю...

Задал вопрос в поиск, но особо точных ответов никто не дал...
Основным минусом CHAR в качестве PK называют то, что при JOIN'ах будет медленней работать, чем при использовании INT.

Но мне JOIN'ов и не надо...
Мне надо, фактически, обновлять данные запросом INSERT UPDATE без доп. выборки SELECT'ом тех Id, которые затрагиваются.
В моём случае, я их могу предугадать со 100% уверенностью...

Во-от...
PM   Вверх
skyboy
Дата 26.11.2012, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 41
Всего: 260



Цитата(fridkaratel @  26.11.2012,  01:41 Найти цитируемый пост)
Мне надо, фактически, обновлять данные запросом INSERT UPDATE без доп. выборки SELECT'ом тех Id, которые затрагиваются.

я тебе уже писал, что составной уникальный ключ на StoreId + CommId позволяет тебе поступать так же.
Цитата(fridkaratel @  26.11.2012,  01:41 Найти цитируемый пост)
Но мне JOIN'ов и не надо...

то есть, SELECT из этой таблицы не происходит? сугубо вставка/обновление? какая странная таблица smile
PM MAIL   Вверх
lomaster
Дата 26.11.2012, 18:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 101
Регистрация: 27.5.2012

Репутация: нет
Всего: 2



Цитата

То есть примерно так:
 зачем тут StoreCommId ?
PM   Вверх
fridkaratel
Дата 27.11.2012, 06:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



@skyboy:
Цитата
я тебе уже писал, что составной уникальный ключ на StoreId + CommId позволяет тебе поступать так же.


То есть, получается, если я создам UNIQUE KEY = StoreId + CommId, то мне можно будет точно также делать INSERT ON DUPLICATE KEY UPDATE?
Если да, то это здорово!
Я просто не знал об этом smile

Тогда многие вопросы отпадают, в т.ч. и использование CHAR в качестве PRIMARY KEY.

Цитата
то есть, SELECT из этой таблицы не происходит? сугубо вставка/обновление? какая странная таблица

SELECT происходит.
Чтобы выдать товар, происходит LEFT JOIN с выборкой кол-ва на складе, чтобы не выдать больше, чем там есть.
Но JOIN происходит не по PRIMARY KEY, а по Id склада и артикулу товара.

----------------------------

@lomaster
Цитата
зачем тут StoreCommId ?


Чтобы обновить кол-во на складе, зная StoreCommId...
Но если можно так, как сказал skyboy, то StoreCommId как-бы и не нужен уже smile

Это сообщение отредактировал(а) fridkaratel - 27.11.2012, 06:45
PM   Вверх
skyboy
Дата 27.11.2012, 08:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 41
Всего: 260



Цитата(fridkaratel @  27.11.2012,  05:32 Найти цитируемый пост)
Я просто не знал об этом

меж тем, я уже дважды об этом писал  smile 
PM MAIL   Вверх
fridkaratel
Дата 27.11.2012, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



@skyboy:
Большое спасибо за ответы и советы! ;-)
Сегодня почитал про ключи и узнал много нового smile

Есть попутный вопрос (перед закрытием темы)...

Чтобы выбрать доступные для резерва товары, я выполняю такой запрос:
Код

SELECT
    сcb.BookingCommodityId,
    сcb.BookingId,
    сcb.BookingQty,
    сcb.Sku,

    sc.StoreQty,

    сcr.ReserveQty,

    SUM(сci.IssueQty) IssueQty,

    cc.Title

FROM
    `client_commodity_booking` ccb

    LEFT JOIN
        `store_commodity` sc
        ON
            sc.StoreId=3
            AND
            sc.Sku=ccb.Sku

    LEFT JOIN
        `client_commodity_reserve` ccr
        ON
            ccr.ManagerId=7
            AND
            ccr.BookingCommodityId=ccb.BookingCommodityId

    LEFT JOIN
        `client_commodity_issue` cci
        ON
            cci.StoreId=3
            AND
            cci.BookingCommodityId=ccb.BookingCommodityId

    LEFT JOIN
        `catalog_commodity` cc
        ON
            cc.Sku=ccb.Sku

WHERE
    ccb.BookingId=100

GROUP BY
    ccb.Sku

ORDER BY
    ccb.Sku


Чтобы выбрать долги клиенту, я выполняю такой запрос:
Код

SELECT
    ccb.Sku,
    SUM(ccb.BookingQty-ccb.IssueQty) DebtQty,
    SUM(ccb.ReserveQty) ReserveQty,

    sc.StoreQty,

    cc.Title

FROM
    `client_commodity_booking` ccb

    LEFT JOIN
        `store_commodity` sc
        ON
            sc.Sku=ccb.Sku
            AND
            sc.StoreId=3

    LEFT JOIN
        `catalog_commodity` cc
        ON
            cc.Sku=ccb.Sku

    LEFT JOIN
        `client` c
        ON
            c.ClientId=ccb.ClientId
WHERE
    ccb.ClientId=10
    AND
    ccb.BookingQty>ccb.IssueQty
    AND
    c.ManagerId=7

GROUP BY
    ccb.Sku

ORDER BY
    ccb.Sku


Возникают два вопроса:
1. Не слишком ли они сложные и..
2. Можно ли их упростить?

Комментарий:
- У каждого клиента есть менеджер, который его обслуживает, поэтому он учавствует и в резерве товара.
- Эти два запроса я подкорректировал для наглядности. То есть, не надо их сопоставлять один с другим. Можно сказать, эти запросы выполняются к двум разным БД с разными структурами таблиц smile

Это сообщение отредактировал(а) fridkaratel - 27.11.2012, 09:43
PM   Вверх
fridkaratel
Дата 29.11.2012, 06:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



В качестве эпилога...

С запросами разобрался.
С использованием CHAR в качестве PRIMARY KEY тоже...

Вывод:
Не использовать CHAR в качестве PK - использовать составной UNIQUE INDEX по тем столбцам, из которых хотелось сформировать PRIMARY KEY.

То есть, если StoreId=3 и CommId=1000, то вместо PRIMARY KEY (AS CHAR) = 3_1000 сделать UNIQUE INDEX на StoreId + CommId.
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | MySQL | Следующая тема »


 




[ Время генерации скрипта: 0.0959 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.