AlaSQL - это библиотека для обработки данных с помощью языка SQL, которая написана на JavaScript и может работать в браузере (в том числе, и в режиме WebWorker) или Node.js. Библиотека может быть использована в приложениях для обработки данных, а также для решения задач ETL (extract-transform-loading), таких как приложения бизнес-аналитики.
AlaSQL позволяет проводить сложные манипуляции с массивами данных (такие как группировки, сортировки, выборки, слияния) с помощью привычных выражений языка SQL. Встроенные процедуры импорта и экспорта данных в различных форматах (включая TXT, JSON, CSV, TSV, Microsoft Excel и Google Spreadsheets) предоставляют удобный интерфейс для импорта и экспорта прямо из SQL-выражений. Библиотека хорошо сочетается с такими современными фреймворками, как Angular.js, d3.js и Google Chars.
AlaSQL поддерживает совместимость по многим операторам со стандартным SQL и различными его диалектами, что позволяет переносить ранее разработанные процедуры для других баз данных. Специальные расширения синтаксиса SQL позволяют простым и удобным способом использовать все возможности, предоставляемые JavaScript, например, обработка JSON объектов из SQL выражений.
Для достижения высокого быстродействия AlaSQL написана с использованием сильно оптимизированного JavaScript и содержит несколько эвристик для сокращения времени обработки SQL выражений.
AlaSQL - SQL библиотека на JavaScript (выступление на PiterJS)
1. AlaSQL
SQL библиотека для обработки данных на JavaScript
Андрей Гершун PiterJS
agershun@gmail.com 14 мая 2015 года
@agershun
1
à la
SQL
2. Содержание
• Зачем нужен SQL на клиенте?
• Как установить AlaSQL?
• Как использовать AlaSQL?
• Решение задач ETL
• Хранение данных на клиенте
• Расширение SQL
• Как устроен AlaSQL?
2
3. Зачем SQL на клиенте?
• Задачи обработки данных
• Выбор (SELECT, REMOVE COLUMNS)
• Сортировка (ORDER BY)
• Группировка (GROUP BY)
• Выборка (WHERE, HAVING)
• Соединение (JOIN)
• Импорт/экспорт в различные форматы
хранения данных (Excel, CSV, TXT,
Google)
• Хранение данных на клиенте
3
4. Почему бы не использовать только
«большие» базы данных?
• Может быть плохая связь
• Хранение данных в памяти клиента
• Быстрый фронт-энд для приложений BI
4
5. Какие решения уже существуют?
• Встроенные базы данных
• WebSQL
• IndexedDB
• SQL на JavaScript
• SQL.js
• SequelSphere
• “Почти” SQL
• Lovefield
• ydb-db
• pouchDB
5
6. Как можно использовать SQL в
программе на JavaScript?
<script src="alasql.min.js"></script>
<script>
alasql("CREATE TABLE cities (
city string, population number)");
alasql("INSERT INTO cities VALUES
('Rome',2863223), ('Paris',2249975),
('Berlin',3517424), ('Madrid',3041579)");
console.log( alasql("SELECT * FROM cities
WHERE population < 3500000
ORDER BY population DESC") );
</script>
6
7. Как с помощью SQL обрабатывать
данные JavaScript ?
<script src=“alasql.min.js”></script>
<script>
var data = [{a:10},{a:2},{a:25}];
var res = alasql(‘SELECT * FROM ? ORDER BY a’,[data]);
</script>
7
8. API
• Синхронный
var res = alasql(‘SELECT * FROM one’,
[params]);
• Асинхронный (для операций с файлами)
alasql(‘SELECT * FROM two’, [params],
function(data,err) {
if(err) console.log(err);
console.log(data)
});
8
9. AlaSQL
Пакеты NPM, Bower, Meteor
Установка:
npm install alasql
bower install alasql
meteor add agershun:alasql
Подключение
<script src=“alasql.min.js”></script>
var alasql = require(‘alasql’);
Зависимости от других библиотек:
• Нет
• xlsx-js, TableTop, AngularJS, Meteor - для отдельных операций
импорта-экспорта
9
11. SQL-92
• SELECT
• INSERT
• DELETE
• UPDATE
• CREATE TABLE
• CREATE VIEW
• CREATE UNIQUE
INDEX
• CREATE DATABASE
• и другие операторы
• Реализованы
практически все
основные операторы
и функциональность
SQL за исключением
триггеров и
ограниченной
поддержки
транзакций
11
12. CREATE TABLE Fruits (
fruitid INT PRIMARY KEY,
fruitname NVARCHAR(MAX),
price MONEY
);
CREATE TABLE Orders (
orderid INT PRIMARY KEY IDENTITY,
fruitid INT REFERENCES Fruits(fruitid),
qty FLOAT
);
INSERT INTO Fruits
VALUES (1,"Peach",22), (2,"Apple",10),(3,"Melon",14);
INSERT INTO Orders (fruitid, qty)
VALUES (1,100), (2,150), (3,25);
SELECT f.fruitname, f.price, o.qty,
f.price*o.qty AS amount
FROM Orders o
INNER JOIN Fruits f USING fruitid;
12
13. Все JOINы на свете…
• CROSS JOIN
• INNER JOIN
• LEFT OUTER JOIN
• RIGHT OUTER JOIN
• FULL OUTER JOIN
• SEMI JOIN
• ANTI JOIN
• NATURAL JOIN
• ON
• USING
• CROSS APPLY
• OUTER APPLY
13
16. Импорт и экспорт данных
(CSV, TAB, XLSX)
SELECT Country, Name
INTO CSV("mydata.csv")
FROM XLSX("cities.xlsx",
{headers:true, range:"B1:E10"})
WHERE Population > 100000',
16
19. Пример: Подготовка данных для
Google Maps из Slideshare.com
Данные
по
просмот
рам
XLSX
(на
сервере)
Гео
данные
по
странам
CSV
(в
Интерне
те)
Данные
по
просмотр
ам
по
странам
с
указание
м
широты
и долготы
Массив
JavaScrip
t
slideshare
.com
github.co
m
Google
Maps API
JOI
N
19
20. SELECT countries.*, views.cnt
FROM (
SELECT Country, COUNT(*) AS cnt
FROM "all_latest_views_3m.csv"
GROUP BY Country
) AS views
JOIN (
SELECT *
FROM "https://abc.com/lat-long-
countries.csv"
) AS countries USING Country
20
21. Сохранение данных в XLS с цветами и
стилями
var mystyle = {
headers: true,
column: {style:{Font:{Bold:"1"}}},
rows: {1:{style:
{Font:{Color:"#FF0077"}}}}
};
alasql('SELECT * INTO XLSXML("rest.xls",?)
FROM ?',[mystyle,data]);
21
22. Alacon - утилита для ETL
> alacon “SELECT 2+2”
4
> alacon “SELECT * INTO 'medals.csv'
FROM 'medals.xlsx' WHERE Year=2008”
22
24. IndexedDB
ATTACH INDEXEDDB DATABASE geo;
CREATE TABLE IF NOT EXISTS geo.country;
SELECT * INTO geo.country
FROM CSV("country.csv",{headers:true});
SELECT * INTO XLSX("asia.xlsx")
FROM geo.country
WHERE continent_name = "Asia"');
24
28. Alasql для d3.js:
Олимпийские медали из Excel
28
alasql('SELECT '+axe+',
SUM([Gold Medals]) AS Gold,
SUM([Silver Medals]) AS Silver,
SUM([Bronze Medals]) AS Bronze
FROM "medals.csv"
GROUP BY '+axe+'
ORDER BY '+axe,[],function (data){
// data - выборка медали по заданной
оси
});
32. Поиск по вложенным JSON объектам
var data = {a:{a:{a:{a:{b:10}}}},b:20};
alasql(‘SEARCH a b FROM ?,[data])
20
alasql(‘SEARCH /* b FROM ?,[data])
[10,20]
alasql(‘SEARCH a? b WHERE(b>=20) FROM ?,[data])
[20]
32
33. Парсер SQL (AST-дерево)
var ast = alasql.parse('SELECT SUM(x)+20
FROM one GROUP BY x');
{ statements: [ {
columns: [{
left: { aggregatorid: 'SUM',
expression:{columnid: ‘x’},
over: undefined },
op: '+’,
right: { value: 20 } } ],
from: [Object],
group: [Object]
} ] }
33
34. Поиск по дереву
var res = alasql(’
SEARCH /+ aggregatorid
FROM ?',[ast]);
['SUM’]
34
35. Графы
CREATE GRAPH Olga, Helen, Pablo,
Andrey, [Alice Cooper],
Olga > loves > #Pablo,
Helen > hates> Andrey,
Pablo > loves > Alice,
Andrey >> Alice
35
36. SEARCH PATH
alasql('SEARCH >> name FROM #Olga');
['Pablo']
alasql('SEARCH >> >> name FROM #Olga');
['Alice']
alasql('SEARCH / >> >> #Alice name');
['Olga','Helen']
36
37. Файл CSV с ребрами графа
source,target,value
Игорь,Зина,1.2
Игорь,Марина,1.3
Сергей,Алиса,0.2
Эва,Алиса,0.5
Петр,Алиса,1.6
Марина,Алиса,0.4
Яков,Алиса,0.6
…
37
38. Загружаем граф
1. Загружаем граф
SELECT * FROM
CSV("forcerus.csv",{headers:true})
2. Определяем вершины
var vv = alasql('SEARCH DISTINCT(UNION
ALL(/[source],/[target])) FROM ?',[data]);
3. Создаем граф
alasql('CREATE GRAPH
'+vv.map(function(v){return '"'+v+'"'}));
38
43. Как устроен AlaSQL изнутри?
• Лексер
• Парсер
• Интерпретатор
• Критические участки
SELECT/INSERT/DELETE/UPDATE/SEARCH
компилируются в JS
43
44. Скорость работы
SELECT SUM(test1.one), test1.two,
test2.three
FROM test1
JOIN test2 ON test1.two = test2.two
WHERE test1.one > 5
GROUP BY test1.two, test2.three
ORDER BY three, sumone
44
46. Оптимизация
• Анализ JOIN и WHERE выражений и преиндексация
FROM one
JOIN two USING e
JOIN three ON two.a = three.a+1 AND two.b =
three.c+three.d
WHERE two.a > 10 AND three.c > 20
• Как сократить пробег?
• one.length x two.length x three.length
• Оптимизиация
• two.e - индекс (хэш) для demo.e
• (three.a+1) +’#’+ (three.c+three.d) – индекс для (two.a) +’#’+
(two.b)
• two.a > 10 – префильтрация массива one
• three.c > 20 – префильтрация массива two
46
47. Прекомпиляция
• Парсинг занимает существенное время
• Можно прекомпилировать операторы заранее
var more = alasql.compile(
‘SELECT COLUMN * FROM ? WHERE _ > ?’);
more([[1,2,3,20,30],10])
[20,30]
47
48. Компиляция
SELECT * FROM data ORDER BY alpha, beta
var orderfns = “
if(a.alpha>b.alpha) {return 1;
else if(a.alpha==b.alpha) return 0;
if(a.beta>b.beta) {return 1;
else if(a.beta==b.beta) return 0;
}}
return -1;”;
var orderfn = new Function(‘a,b’, orderfns);
var data = data.sort(orderfn);
48
49. Выбор методов JavaScript
• for быстрее, чем forEach и т.д.
• some быстрее, чем filter()
• parseInt(x,10) быстрее, чем x|0
jsPerf.com - лучший советчик…
49