"alasql.js — база данных sql на javascript" — Андрей Гершун,...
TRANSCRIPT
Alasql.jsбаза данных SQL
на JavaScriptАндрей Гершун
https://github.com/agershun/alasql
MoscowJS
29 января 2015 года
à la
SQL
1
1. Что такое Alasql.js?
2. Примеры использования Alasql
3. Alasql изнутри
4. Оптимизация
“Alasql - à la SQL parce que le monde entier envie notre belle langue”
Maxime Bertonnier, blogwebdev.fr
2
Ты помнишь, каквсе начиналось…
lodash v3.0.0_.sortByAll(collection, props)
3
Alasql.js – SQL на JavaScript?… Хм.
• Сложные SQL запросы и быстрая обработка данных на клиенте:• WHERE
• GROUP BY
• HAVING
• ORDER BY
• JOIN
• APPLY
• CSV, TAB, XLS, JSON
4
Применение
• Фронт-энд для Business Intelligence приложений • OLAP
• таблицы
• Client First • мобильные приложения с
неустойчивой связью с сервером
5
Какие клиентские SQL базы данныхсуществуют для JavaScript?• «Полноценные» SQL
• WebSQL (SQLite) – «вне стандарта» с 2011 года • SQL.js (SQLite) – (1.5 Мб), Emscripten, небыстрый• SequelSphere.js – закрытый код
• LINQ• SQLike.js• JSLinq.js и др.
• NoSQL • IndexedDB• Key-value хранилища• PouchDB, ydn-db• CrossFilter.js
6
Подключение Alasql.js
Браузер
<script src=“alasql.js></script>
<script>
alasql(‘CREATE DATABASE test01’);
</script>
AMD или UMD
require([‘alasql’], function(alasql) {
alasql(‘SELECT * FROM courses’);
});
Node.js
npm install alasql
var alasql = require(‘alasql’);
7
Использование Alasql
Синхронный интерфейс:
var res = alasql(sql, params);
Асинхронный интерфейс:
alasql(sql, params, function(res, err) {
// res – результаты, err - ошибка
});
8
Пример выполнения SQL-операторов
alasql('CREATE DATABASE TEST01; \
USE TEST01; \
CREATE TABLE jedi ( \
jediid INT, \
name STRING \
); \
INSERT INTO jedi VALUES \
(100, “Анакин Скайуокер")'
);
Перевод на JavaScript
var jedi = [];
jedi.pop({studentid: 100, name:‘Анакин Скайуокер'});
9
Пример SQL-запроса
var num = alasql('SELECT VALUE COUNT(*) FROM jedi');
Перевод на JavaScript
var num = jedi.length;
10
Реализованная функциональность SQL• WITH SELECT TOP INTO FROM GROUP BY HAVING WHERE LIMIT FETCH
• SUM, COUNT, DISTINCT, MIN, MAX, FIRST, LAST
• ROLLUP(), CUBE(), GROUPING SETS()
• INNER LEFT RIGHT OUTER SEMI ANTI NATURAL CROSS JOIN
• UNION ALL EXCEPT INTERSECT
• CROSS OUTER APPLY
• Вложенные SELECT, EXISTS, ANY, SOME
• INSERT DELETE UPDATE
• CREATE DROP ATTACH USE DATABASE, SHOW DATABASES
• CREATE DROP TABLE, PRIMARY KEY, CREATE DROP VIEW
• IF ELSE WHILE BEGIN END
• DECLARE SET
• BEGIN COMMIT ROLLBACK TRANSACTION (ограничено)
• Стандартные функции, CAST/CONVERT
• a la LINQ (fluent interface)11
Реализованная функциональность SQL
•ROLLUP, CUBE, GROUPING SETS
• INNER LEFT RIGHT OUTER SEMI ANTI NATURAL CROSS JOIN
•CROSS OUTER APPLY
•Вложенные SELECT, EXISTS, ANY, SOME
12
SQL и JavaScript – лучше вместе!
13
var data = [[1,2,3], [2,3,4], [5,6,7]
];var res = alasql('SELECT * FROM ? \
WHERE [0] < ?',[data, 2]);
Перевод на JavaScriptvar res = data.filter(function(d){return d[0] < 2});
Сколько строк нужно на JavaScript,чтобы реализовать SQL запрос?SELECT COUNT(*) FROM students
LEFT JOIN courses USING courseid
LEFT JOIN schools ON students.schoolid = schools.schoolid
WHERE courseid > 3
GROUP BY schools.schoolid, courses.courseid
ORDER BY courseid DESC, schoolid
Инструменты JavaScript:• filter(), sort(), map(), reduce(), every(), some() … - непросто…
14
Сахар…
alasql(‘SELECT LEN(_) FROM “mytext.txt”’);
Результат: длины строк в файле mytext.txt
15
Работа с объектами и функциями JavaScript
var data = [
{a:{b:[1,2,3,4]},
{a:{b:[2014,2015]}}
];
alasql(‘SELECT a->b->length FROM ?’,[data]);
Результат: [4,2]
16
Загрузка данных из файлов в браузере,
Загрузка данныхс сервера
Загрузка данныхс десктопа
Экспорт данныхна десктоп
Источники данных:• JSON• CSV, TAB• XLS, XLSX• Google Spreadsheets• HTML (тэг <table>)
17
18
19
Alasql для d3.js:Олимпийские медали из Excel
20
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 - выборка медали по заданной оси
});
21
22
23
24
Пример: Подготовка данных для Google Maps из Slideshare.com
Данныепо
просмотрам
XLSX(на сервере)
Гео данныепо странам
CSV(в Интернете)
Данныепо
просмотрампо странамс указанием
широтыи долготы
МассивJavaScript
slideshare.com
github.com
GoogleMaps APIJOIN
25
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
26
Alasql из консоли: Простой ETL
> node alacon “SELECT 2+2”
4
> node alacon “SELECT * INTO 'medals.csv'
FROM 'medals.xlsx' WHERE Year=2008”
27
SQL2: Alasql вместе с IndexedDB(а также Local Storage, File Storage, SQL.js)
28
CREATE INDEXEDDB DATABASE IF NOT EXISTS geo;
ATTACH INDEXEDDB DATABASE geo;
USE geo;
DROP TABLE IF EXISTS cities;
CREATE TABLE cities;
SELECT * INTO cities FROM ?;
SELECT COLUMN * FROM cities WHERE population > 100000 ORDER BY city DESC
A la LINQ. Текучий интерфейс ;)var data = [{a:1,b:1},{a:2,b:-1},
{a:3,b:3},{a:1,b:5}];
var res = alasql(data).Top(2).GroupBy("a").exec();
29
Alasql в обычном режиме<script src="alasql.min.js"></script>
<script>
var arr = [{a:1},{a:2},{a:1}];
alasql('CREATE TABLE one (a INT); \
INSERT INTO one VALUES(10); \
SELECT * INTO one FROM ?; \
SELECT * FROM one',[arr], function(data){
// Выполняется в основном потоке
});
</script>30
Alasql в Worker<script src="alasql-worker.min.js"></script>
<script>
var arr = [{a:1},{a:2},{a:1}];
alasql('CREATE TABLE one (a INT); \
INSERT INTO one VALUES(10); \
SELECT * INTO one FROM ?; \
SELECT * FROM one',[arr], function(data){
// Выполняется в основном потоке
});
</script>31
Alasql изнутри
1. Лексер и парсер• Jison
2. Интерпретатор• Интерпретация «больших» операторов
(CREATE DATABASE, CREATE TABLE и др.)
3. Компилятор• Компиляция «критичных по скорости»
операторов SELECT/INSERT/UPDATE/DELETE
32
Оптимизация запросов
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
33
34
http://jsperf.com/alasql-js-vs-websql/7
Оптимизация SQL• Анализ JOIN и WHERE выражений и преиндексация
FROM oneJOIN two USING eJOIN three ON two.a = three.a+1 AND two.b = three.c+three.dWHERE 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
35
Компиляция критических операций(SELECT, WHERE, ORDER BY, GROUP BY, HAVING, INSERT, DELETE, UPDATE):
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);
36
«Классическая» оптимизация JavaScript
• for быстрее, чем forEach и т.д.
•some быстрее, чем filter()
•parseInt(x,10) быстрее, чем x|0
jsPerf.com - лучший советчик…
37
Тестирование
•Mocha.js
•240+ тестов для Node.js и браузера
•Нужно не менее 2000…
38
@agershun
GitHub
• https://github.com/agershun/alasql
Что дальше?
39