Cast

4 отговора 390 прегледа
#1

Cast

Опитвам се да направя скрипт, който проверява принадлежност на IP към мрежа със SQL заявка. Разполагам с bigint ip, network и subnet mask, НО имам проблем.

Резултатът от битово в mysql & e SIGNED bigint, а на мен ми трябва UNSIGNED bigint. От Cast няма полза. Усещам в случая общотеоретична липса, SOS?

Реално ми трябва число, което като го извадя от signed bigint и да получа онова, което би било, ако резултатът от bitwise операции беше unsigned bigint:)

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

Re: Cast

Еми, да живее калкулатора. Търсеното число е 2147483648, приложено на данните, а не на SQL query-то, което стана много бързо. Така и трябва, защото му предстои да се изпълнява често.

Може да пробвате дали съм постигнал коректно разпознаване на IP-та на [линк]

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

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

Re: и добре и лошо :)

Добре е, че си се преборил макар, че не си особено прав.

Първо резултатът от
x & y
винаги е BIGINT UNSIGNED

SELECT 0xffffffffffffffff & 0xffffffffffffffff;
+-----------------------------------------+
| 0xffffffffffffffff & 0xffffffffffffffff |
+-----------------------------------------+
| 18446744073709551615 |
+-----------------------------------------+


Или ако искаш така:

mysql> SELECT @x := INET_ATON('10.10.10.20') & INET_ATON('255.255.255.0') AS x;
+-----------+
| x |
+-----------+
| 168430080 |
+-----------+
1 row in set (0.00 sec)

mysql> SELECT HEX(@x), INET_NTOA(@x);
+---------+---------------+
| HEX(@x) | INET_NTOA(@x) |
+---------+---------------+
| A0A0A00 | 10.10.10.0 |
+---------+---------------+
1 row in set (0.00 sec)

Което общо взето е каквото ти трябва.

Съгласен ли си дотук?

Второто е доста по-весело.

Ако сравняваш колонка от таблица маскирането по "обичайния" начин е адски лош вариант. Просто защото
SELECT ... WHERE ip & INET_ATON('255.255.255.0') = INET_ATON('10.10.10.0');

или еквивалентното
SELECT ... WHERE ip & 0xFFFFFF00 = 0xA0A0A00;
никога ама никога няма да използваникакъв индекс.

Затова е много по-добре да постъпиш по най-хамалския начин и да проверяваш обхват от числа т.е. горното става

SELECT ... WHERE ip BETWEEN INET_ATON('10.10.10.1') AND INET_ATON('10.10.10.254');

или какъвто и да е еквивалентен вариант.


Знам, че за всеки програмист това звучи много по-дървено, но така индексите работят. А когато имащ да преравяш таблица с 2 милиона IP адреса определено ще предпочетеш да го правиш чрез индекс. нали така?


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

Re: и добре и лошо :)

Освен ако намерените съвпадения не са 1.9 млн...

Everything louder than everything else...
Отговор
в отговор на salle #5

Re: и добре и лошо :)

Много благодаря, тайно се надявах да намериш темата за интересна :)

Базата ми няма да се усложни от тази промяна. В момента съхранявам 2 полета - за ip и за subnet mask, вместо subnet mask трябва да сложа най-голямото ip от мрежата и да добавя индекс.

Мислих донякъде стереотипно, защото предната версия на това ми нещо беше с парсване на файл, в който мрежите са във формат
194.12.244.0/19

Сега обаче ще го изпълнявам 30 - 40000 пъти дневно и вече стана важно да е направено добре.

Още веднъж благодаря!

Отговор