select in

10 отговора 391 прегледа
#1

select in

Как мислите ако ми се падат много id в една заявка например select * from t1 where t1.id in (1,2,3,4,5.....) не е ли по добре да помисля за друг дизайн на базата. Тези айдита се генерират динамично и понякога достигат до 100-200.
Въпроса е една такава заявка повече изчисления ли изисква на ниско ниво от една заявка спрямо индекс който е в една колона от таблица например.
Т.е. тези 1,2,3,4,5 да са редове от таблица с колона 'тип' и някакъв индекс в нея.

Отговор
в отговор на emb #2

Re: select in

where t1.id in (1,2,3,4,5.....) се привежда до where t1.id =1 or t1.id =2........
а с допълнителна таблица ще стане с join.
Т.е. втория начин ще е по-ефективен, но....(живота щеше да е прекрасен, ако нямаше но) ще загубиш време за създаването и. Така че отговора е - зависи. Тестовете ще покажат истината.

От индекси във втората таблица едва ли ще има полза. При толкова малко стойности вероятно индекса няма да се ползва.

Редактирано от NDeu на

Отговор
в отговор на NDeu #3

Re: още некои съображения ...

Като начало има 3-ти вариант, но е много специфичен.

Незнайно защо много често такива генерирани списъци всъщност могат да се приведат до обхват от числа.

> например select * from t1 where t1.id in (1,2,3,4,5.....)

Та значи ако случая ти е точно такъв най-добре е да го заменищ с
WHERE t1.id BETWEEN 1 AND 5

Естествено това е частен случай.


Та значи по въпроса дали е по-добре дълъг списък в IN() или отделна таблица и JOIN както каза NDeu зависи. Най-добре да пробваш. И двете си имат и добри и лоши страни.

Отделната таблица има едно много голямо предимство - можеш да я използваш в много заявки (вместо да изпращаш големия IN() списък)

Ако се замислиш това може и да е от решаващо значение примерно за Уеб приложение.
Прледстави си списъка се генерира в една Уеб форма и после се предава нататък ..... въпрос и на вкус, но на мен ми се струва по-елегантно да предавам само име на таблица отколкото нейзайно колко дълъг списък ....

За такива цели най-добрия тип таблица е HEAP. При 100-200 реда направо без индекс. При няколко хиляди - пробваш. Индекс едва ли ще помогне, но пък знаеш ли ...

salle.online.bg/sig
Отговор
в отговор на emb #4

Re: select in

Е то все пак си зависи и от бозата де ? Аз никъде не разбрах какво седи отдолу?

Иначе варианти много, но ако тези ид-та от както се вижда са уникални, и правят рейндж някакъв най-добре е с битуин...енд... да се действа.

Ако не са тогава по-добра идея е да флатнеш леко базата като добавиш някое поле, в което да кисне някакъв флаг за съответните ид-та, ако разбира се ги подбираш по критерии.

Джойна освен ако не е по полета, по които и в двете таблици има индекси ще бъде по-бавен (а дори и да има индекси пак ще е по-бавен).

Освен това ако има индекс, той очевидно ше се използва. При 'МС'СеКЮЕЛ най-ефективно е например полетата, които дърпаш от базата да са в индекс-а, тогава даже не се обръща, към дейта пейджовете, а смъква данните направо от индекса. При клъстерд индекс па е още по-бързо ;)
Но при този "селект *" това очевидно не върши работа.

Отговор
в отговор на synchu #5

Re: select in

Благодаря на всички за коментара. Всъщност дадох неуместен пример с поредни числа защото те всъщност са произволни така че за обхват с between не става.
Всъщност дилемата е дали да си флатна базата и добавя едно допълнително поле с флагове и да стане както трябва или да правя свободни съчинения на тема бази данни :).
Защото в момента тези ай-дита се съхраняват в мемо(текст) поле и трябва допълнително да се обработват от скрипт който ги подава на заявка select in.
В дизайна на базата и специално на тази таблица , този подход осигурява голяма гъвкавост откъм избор на възможности за комбинация на достъпни ресурси ,ай-дитата, защото много от тях присъстват в по-вече от един резултат на тези заявки .
Пример - имам 100 души , всеки един от тях участва в най-различни групи.
Всяка група се конфигурира динамично от администратор като текучеството в във всички групи е голямо и участието на един човек е в повече от една група.Вместо да създавам флаг на всяка група и да повтарям ред с ай-дито на човека аз създавам комбинациите със select in защото пък тези юзъри принадлежат към категории които имат други относително постоянни критерии за които съм използвал този подход .

Отговор
в отговор на emb #6

Re: select in

Ами, все пак крос таблици мисля, че са доброто решение, тези таблици ще ти съдържат примерно:

UserID INTEGER
GroupID INTEGER
Rights SET(canRead,canWrite,canBrowse,......)

праскаш си един индекс UNIQUE по (UserID, GroupID, Righgts)

и след това със JOIN или SUB-SELECT, зависи там каквото ползваш за DBServer, щото нали знаеш :)

Отговор
в отговор на Waflata #7

Re: select in

опааа...мемо-кое ? ;)
Ти и индекс не може да му изковеш на това, като хората...

В този случай следва наистина да се помисли за редизайн на бозата и ако става въпрос за групи/юзъри/роли/пермишън ид-та най-доброто (според мен де;) ) решение е всичките да се разделят по таблици:

таб1:
Юзър; Юзър Име
таб2:
Група, Група Име
таб3:
Юзър;група
таб4:
група;<обдж или там пермишън или квото е там ид-то>

слагаш индекси на цялата тая постановка и джойнове ;)

Отговор
в отговор на synchu #8

Re: select in

Значи групите с пермишъните на юзърите така или иначе са в отделна таблица и там тези групи са относително по рядко променяни. Те са джойн с основната таблица.
Експериментираме фактически още един подход в комбиниране на юзърите относно групи с голяма динамика по друг критерий, като на практика така се пести създаването на нови редове, а вместо това се използват вече налични.
Мисълта ми беше ако изписваме вежди, дали не вадим очи. Т.е. създаването и изчитането на нови редове в базата сравнено със съпоставянето на всички тези ай-дита във in() спрямо наличните в таблицата не представлява ли голям овърхед за сървъра и това като краен резултат да води до по-тромава информационна система, вместо изчитането им спрямо някакъв флаг, съответно индекс.

Отговор
в отговор на emb #9

Re: select in

Все още не мога да си формирам някаква пълна картинка на ситуацията - ама нема лошо ще продължаваме напред с вариантите ;)

пишем тогава един дроп на предишния ми стейтмънт...

Флаг + съответен индекс е за мен най-бързия вариант + че е лесен за поддръжка и обработка. Но разбира се зависи от много неща - какъв е типа на полето за флага, каква е честотата и обхвата на модификациите по полето.
За селекта съмнение няма, че ще бъде по-бърз.

Създаването и изчитането на редовете въобще не е толкова бавно (е зависи де сега ако създаваш 5000 реда в сек. е проблем).
Но тъй като в общия случай специално при пермишън реализациите най-ключовия момент е бързина при четенето. Ако даден потребител си цъка кротко по менютата и бутончетата и софтуера проверява само пермишъните по 1-2 сек тва е много.
Т.е. аз бих го оптимизирал от тази гледна точка - четенето.
Колко динамично/често е това обновяване ? ??? Колко е теоретичния максимум на редовете в таблицата???

И пак казвам зависи и от бозата отдолу.
Но при всички случаи ако мемо-поле ти е в where клаузата нещата стават дебели и като принцип трябва да се избягва.

There are 10 types of people in this world one who understand binary jokes and one who not
Отговор
в отговор на emb #10

Re: в допълнение към коментарите на synchu

Независимо за кой продукт иде реч никога не се колебай да предпочетеш добавянето на ред(ове) пред усложнена структура или претоварени стойности в колонките.


С две думи Релационните Бази Данни са пригодени (изначално) да работят много по ефективно с таблици които имат малко колонки и огромен брой редове отколкото с таблици с мнооооого колонки и малко редове.

Както казваше някой
- Надолу по таблицата можещ да индексираш ама я се опитай да индексираш надясно да те видим!

salle.online.bg/sig
Отговор
в отговор на salle #11

Re: в допълнение към коментарите на synchu

10x

Отговор