Попробуйте вычислить в уме:
(5-5)*(17/(345-34,458)-242299)
Полагаю, вы затратили на вычисление не больше двух секунд, верно? А все потому, что вы знаете арифметическое правило: при умножении на ноль любого числа получится ноль. Зная это, вы попросту не стали вычислять второй множитель, а сразу назвали результат.
Если вы еще не знали, я раскрою вам небольшой секрет: вычислительное ядро файлмейкера (calculation engine) тоже знает это арифметическое правило. И его, и другие правила он применяет, чтобы сократить время вычислений.
Какая нам от этого секрета польза, спросите вы? У нас что, регулярно в файлмейкере применяется умножение на ноль?
Арифметики действительно в filemaker не много. Зато filemaker регулярно производит логические вычисления, которыми вы его нагружаете. Логические операции очень просты, но имеют свои хитрости. Если знать их и применять в построении выражений, то можно значительно повысить производительность приложений.
Файлмейкер выполняет четыре логические операции и использует четыре логических оператора: AND, OR, XOR и NOT.
Вот примеры логических вычислений:
If(Order::date = Get(CurrentDate) AND Order::total > 0; 1)
If(Order::date = Get(CurrentDate) OR Order::total > 0; 1)
В логических выражения все, что находится слева и справа от логического оператора, рассматривается приложением как элемент особого типа: булево. Эти элементы, независимо от того, что они в себе содержат и как выглядят, всегда будут интерпретироваться как Истина или Ложь (1 и 0). В конечном счете логические операции — это операции с двумя числами: один и ноль. А результат вычисления —всегда тоже единица или ноль.
Основные логические операции можно свести в таблицы, которые называют еще таблицами истинности
Таблицы истинности
С отрицанием вроде бы все понятно и просто. С исключающей дизъюнкцией (XOR) мы практически не работаем. А вот первые две операции нам определенно стоит изучить поподробнее. В них самая фишка зарыта.
Взглянем внимательно на две верхние таблицы.
Оператор AND в одной из них и оператор OR в другой вполне можно заменить на арифметический оператор, и «истинность» таблиц при этом не нарушится.
Действительно, AND можно заменить на знак умножения. А OR можно заменить на знак сложения. Смотрим
Не случайно конъюнкцию называют иначе «логическим умножением», а операцию OR называют «логическим сложением».
Все. Теперь вспоминаем арифметику младших классов, основные правила для умножения и для сложения. Для умножения ключевой элемент (множитель) — ноль. Сколько на ноль ни умножай, результат будет все равно ноль.
Для сложения ключевой элемент (слагаемое) — единица. Что к единице ни прибавляй, ноль уже не получится (в наших таблицах отрицательных чисел нет).
Что это означает? Элементарно: в половине случаев для того, чтобы вычислить весь результат, достаточно посчитать первый элемент. Смотрим на таблицы снова.
Мы выделили заливкой в таблицах те строки, в которых для вычисления результата требуется просчитать лишь один первый элемент.
Это правило. Такое же, как в арифметике — умножение на ноль
Если при выполнении логического умножения (AND) окажется, что первый элемент (A) равен нулю, то и весь результат равен нулю.
Если при выполнении логического сложения (OR) окажется, что первый элемент (A) равен единице, то и весь результат равен единице.
Все, что нам нужно знать о поведении вычислительного модуля в FileMaker:
а) Он производит вычисление всегда слева направо. Первым вычисляется элемент А, вторым — элемент B.
б) при вычислении логических операций процессор учитывает описанные выше правила. Если для получения результата не требуется вычислять правый элемент B, то он и не будет вычисляться!
Теперь мы знаем, как повысить быстродействие приложение и убрать «тормоза». Все просто. Допустим, у вас есть выражение, в котором перед логической операцией вычисляются два значения.
If(Order::date = Get(CurrentDate) OR Order::total > 0; 1)
Посмотрите, какое значение проще всего вычислить, и ставьте его слева. Используйте принцип: все, что быстрее и проще вычисляется, размещаем левее. Все, что вычисляется дольше и сложнее — размещаем правее.
Но это еще не все.
Представим, что у нас есть два одинаково «тяжелых» вычисления (обозначим условно A и B). Будет ли важен порядок, в котором мы их прописываем в формулах файлмейкера? Ведь результат не меняется от этого (свойство переместительности):
A NOT B = B NOT A
A OR B = B OR A
A XOR B = B XOR A
На самом деле порядок повлияет на быстродействие и в этом случае, а в некоторых ситуациях это будет особенно заметно. Рассмотрим эти ситуации.
Допустим, мы используем знакомую нам формулу.
If(Order::date = Get(CurrentDate) OR Order::total > 0; 1)
Представим себе, что нам нужно это вычисление произвести n раз для N записей. Например, мы используем цикл или эта формула применяется в условном форматировании на странице типа «список». Допустим, у нас в цикле/в списке тысяча записей, и вычисление будет проводиться тысячу раз:
If(Order::date = Get(CurrentDate) OR Order::total > 0; 1)
If(Order::date = Get(CurrentDate) OR Order::total > 0; 1)
If(Order::date = Get(CurrentDate) OR Order::total > 0; 1)
…
If(Order::date = Get(CurrentDate) OR Order::total > 0; 1)
Понятно, что не во всех строчках Order::date = Get(CurrentDate) будет высчитываться одинаково. Скорее всего, большая часть массива (допустим, 99%) даст результат False, а вот несколько самых последних записей будет вычислено как True.
А Order::total > 0 для большей части записей будет вычислено как True.
Что получается? Поскольку у нас операция логическое сложение, а первый элемент в 99% записей дает результат ноль, то для большей части записей придется выполнить и вычисление второго элемента: Order::total > 0
А если в формуле поменять A и B местами, то результат совсем другой
If(Order::total > 0 OR Order::date = Get(CurrentDate); 1)
Теперь файлмейкер будет тысячу раз высчитывать Order::total > 0, но поскольку это практически всегда единица, то Order::date = Get(CurrentDate) вычислять практически не придется. То есть мы записали формулу таким образом, что файлмейкер будет делать на тысячу операций меньше. В ситуации, когда приходится обрабатывать большое количество записей, — это значительный выигрыш во времени.
Итак, второй принцип написания формул с логическими операциями. Если приходится вычислять одинаково сложные выражения, то определите вероятность, с которой выражение вычисляется как 1 или 0.
Если у вас оператор OR, то поставьте перед ним выражение, которое чаще всего или вероятнее всего выдаст результат 1.
Если в формуле оператор AND (логическое умножение), то поставьте перед ним выражение, которое чаще всего или вероятнее всего выдаст результат 0.
И будет вам быстродействие
Примечание. Если кто-то хочет копать еще дальше в эту сторону, то можно изучить правила преобразования логических выражений в СКНФ и СДНФ.
Примечание 2. Это тоже было озвучено в обзорном докладе Аркадия Перла, но уместно напомнить еще раз.
Вычислительный модуль файлмейкера использует аналогичный принцип, когда обрабатывает функцию Case(): он производит вычисления всех кейсов строго по порядку, и завершает работу как только встречает самый первый кейс, удовлетворяющий заданному условию.
Например,
Case(
case1; result1;
case2; result2;
case3; result3;
case4; result4;
case5; result5;
case6; result6;
case7; result7;
)
Файлмейкер не станет считать кейсы 4-7, если case3 возвращает ИСТИНА. Он возьмет результат этого кейса и сразу завершит вычисление. Поэтому разумно размещать кейсы упорядоченно от наиболее простых для вычисления (вначале) до самых сложных в конце.