Страницы

Поиск по вопросам

понедельник, 4 марта 2019 г.

Insert большого количества строк Oracle

Есть задача загрузки csv файла через Web интерфейс. Во время загрузки на стороне клиента выполняются проверки на корректность данных в файле. Сейчас мы вставляем миллионы строк вызывая процедуру вставки одной строки. То есть, для каждой строки файла вызывается процедура. Схематичный вид процедуры:
procedure example(iValue1 IN Table.column1, iValue2 IN Table.column2, iValue3 IN Table.column3) is begin insert into table(column1, column2, column3) values (iValue1, iValue3, iValue3); end;
Вызов миллионов раз это процедуры работает непозволительно медленно. Как можно изменить подход для ускорения процесса вставки?


Ответ

Если нет возможности воспользоваться SQL*loader или insert from External Table, то можно попробовать использовать bulk insert
DECLARE TYPE prod_tab IS TABLE OF products%ROWTYPE; products_tab prod_tab := prod_tab(); start_time number; end_time number; BEGIN -- Populate a collection - 100000 rows SELECT * BULK COLLECT INTO products_tab FROM products;
EXECUTE IMMEDIATE 'TRUNCATE TABLE products'; Start_time := DBMS_UTILITY.get_time; FOR i in products_tab.first .. products_tab.last LOOP INSERT INTO products (product_id, product_name, effective_date) VALUES (products_tab(i).product_id, products_tab(i).product_name, products_tab(i).effective_date); END LOOP; end_time := DBMS_UTILITY.get_time; DBMS_OUTPUT.PUT_LINE(‘Conventional Insert: ’||to_char(end_time-start_time));
EXECUTE IMMEDIATE 'TRUNCATE TABLE products'; Start_time := DBMS_UTILITY.get_time; FORALL i in products_tab.first .. products_tab.last INSERT INTO products VALUES products_tab(i); end_time := DBMS_UTILITY.get_time; DBMS_OUTPUT.PUT_LINE(‘Bulk Insert: ’||to_char(end_time-start_time)); COMMIT; END;
Примеры использования BULK COLLECT и FORALL...

Сделать ячейку таблицы ссылкой

Решил использовать fancyBox3 для вывода изображений. Но возникла проблема в том, что кнопки на моем сайте оформлены через и onclick. А по этой библиотеке используется тег , как можно обернуть ячейку так, чтобы она вся была ссылкой, при этом бы работал скрипт? Простое не работает.
UPD: Судя по документации, это работает так:

Мне же нужно, чтобы работало так:
Ячейка 1
При этом бы клик считался при нажатии любой части ячейки.


Ответ

td{ border: 1px solid; width: 150px; }

Ячейка-ссылка 1.2
2.1 2.2

Постоянное подключение на PHP со свойствами LongPolling и WebSocket

LongPolling работает так, что клиент подключается к серверу по протоколу http(s) и зависает, пока сервер не ответит. После этого создается новое подключение. Это подключение происходит абсолютно стандартным образом с отправкой всех заголовков и cookie. Для каждого такого подключения апач (или другой сервер) создает изолированный процесс.
WebSocket в свою очередь подключается к специальному серверу по отдельному протоколу ws(s). Выходит, что есть всего один процесс, в котором должна проходить авторизация, и велика вероятность утечек памяти. Но преимущества этого подхода в том, что есть постоянное подключение, что обеспечивает моментальную реакцию на события. Помимо прочего, в случае работы с WS не обязательно хранить сообщения где-то в БД, чтобы ничего не было потеряно при переподключении.
Вопрос вот в чем: есть ли что-то среднее между LP и WS?
Работает по протоколу http(s) со всеми плюшками (headers и cookies) Можно написать простой PHP скрипт, который будет запускаться по запросу и обрабатывать все эти подключения, а не пилить полноценный WS сервер, который нужно будет еще мониторить и следить за тем, чтобы он правильно работал. (P.S. Я в проекте единственный разработчик/дизайнер/верстальщик/сис.админ/другое слово, поэтому не хочется добавлять себе еще хлопот) Для каждого подключения спаунит отдельный процесс, изолированный от других подключений Имеет постоянное подключение. И чтобы можно было отправлять сообщения хотя бы в одну сторону (сервер => клиент)

Подробнее о том, в чем собственно проблема.
В проекте используется framework Yii2 с местной системой авторизации и со всеми его плюшками. Описанный мною подход позволил бы мне аутентифицировать пользователя встроенными в framework методами, а саму логику внедрить в action контроллера.
В противном случае мне нужно будет написать отдельный сервер или использовать готовое решение и как-то интегрировать его с фреймворком.
Смотрел в строну Workerman. Опять же возникает вопросы аутентификации, поддержки сервера в рабочем состоянии при утечках и крашах (supervisord?), перезапуска при деплое
Если я где-то заблуждаюсь, тыкните, пожалуйста, пальцем.


Ответ

Достойных альтернатив для WebSocket в наше время считайте что нет. Или WebSocket, или всевозможные костыли. Если без костылей, то...
Первое, что нужно сделать: настроить nginx для передачи WebSocket соединений дальше по цепочке. Так, все ваши клиенты будут работать с nginx, а не напрямую с вашими другими про­граммами. Сохраняются и используются все достоинства nginx. Не нужно использовать выде­ленный порт. Не нужно настраивать HTTPS дважды. Не нужно перезапускать какие-то другие про­граммы после обновления сертификатов Let's Encrypt.
Настройка делается в четыре строчки:
location /mywsapp { proxy_pass http://mywsbackend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
Дальше, нужна альтернатива самостоятельной обработке входящих соединений WebSocket. Такая программа будет брать на себя обработку входящих WS соединений во всей их слож­ности, оставляя вам лишь обработку входящих сообщений и отправку исходящих.
websocketd
Например, программа websocketd работает как inetd, только для процессов. При новом соеди­нении запускается ваша программа, которой нужно читать стан­дартный вход и писать в стан­дартный выход. Можно не читать, только писать. Пример использования в другом ответе.
"; }
Всевозможные заголовки, которые отправляет ваш клиент, доступны через переменные окру­жения. Например, куки видны в $_ENV['HTTP_COOKIE'] и так далее.
Вашим требованиям в части запуска процесса по факту подключения этот подход соответ­ствует. Есть недостатки: если вам повезёт вырасти до сотен или тысяч одномоментных под­ключений, то это будет означать сотни и тысячи висящих в памяти процессов PHP. Впрочем, об этом можно будет подумать потом.
Кроме ограничений по памяти, постоянно работающие процессы PHP создают ещё одну проблему: если вам захочется обновить их логику, то вам потребуется механизм отключения всех таких процессов.
nchan
Если забыть про некоторые требования, то модуль nchan для nginx может ещё больше аб­стра­гировать работу с сообщениями. Для каждого подключающегося клиента вы выделяете какой-то длинный и секретный ID (что-то типа номера почтового ящика), по которому тот подключается к nchan и ждёт сообщения. Вы, со своей стороны, по этому же ID отправляете сообщения по простому HTTP. Если у вас появится больше одного сервера, то забирать сообщения nchan может из Redis.
Установка проще не может быть:
sudo apt install libnginx-mod-nchan
Пример конфигурации.
Недостатки: увеличенная сложность конфигурации nginx и всей архитектуры системы, необходимость хранить идентификаторы клиентов за пределами $_SESSION.
Достоинства: не нужно для каждого соединения держать процесс PHP.

Список будет пополняться.

пятница, 1 марта 2019 г.

Можно ли упростить цикл, используя java 9 или java 8?

Можно ли как-то упростить этот цикл, используя java 9 или java 8?
for (String s : list) { if (s.indexOf("D") != -1) { numberList.addAll(getDoubleFromString(s)); } else { if (s.indexOf(".") != -1) { numberList.add(new TypeSatellite(BigDecimal.valueOf(Double.valueOf(s)))); } else { numberList.add(new TypeSatellite(Integer.valueOf(s))); } } }


Ответ

Давай-те сделаем оптимизации по шагам (основная сложность непонятно что принимают TypeSatellite и какой тип у numberList, поэтому напишу для object'a):
1) Можно заменить s.indexOf(...) != -1 на s.contains(...), то есть записать что-то вроде
list.forEach(s -> { if (s.contains("D")) { numberList.addAll(getDoubleFromString(s)); } else { if (s.contains(".")) { numberList.add(new TypeSatellite(BigDecimal.valueOf(Double.valueOf(s)))); } else { numberList.add(new TypeSatellite(Integer.valueOf(s))); } } });
2) Можно вынести общий код
list.forEach(s -> { if (s.contains("D")) { numberList.addAll(getDoubleFromString(s)); } else { Object number = s.contains(".") ? BigDecimal.valueOf(Double.valueOf(s)) : Integer.valueOf(s); numberList.add(new TypeSatellite(number)); } });
3) Вынесем общий функцию:
list.forEach(s -> { numberList.addAll(getListNumber(s)); }); }
private static Collection getListNumber(String s) { if (s.contains("D")) { return getDoubleFromString(s)); } else { Object number = s.contains(".") ? BigDecimal.valueOf(Double.valueOf(s)) : Integer.valueOf(s); return Collections.singleton(new TypeSatellite(number)); } }
4) последний шаг используем стрим
numberList = list.stream().flatMap(::getListNumber ).collect(Collectors.toList());
private static Stream getListNumber(String s) { if (s.contains("D")) { return getDoubleFromString(s).stream(); } else { Object number = s.contains(".") ? BigDecimal.valueOf(Double.valueOf(s)) : Integer.valueOf(s); return Stream.of(new TypeSatellite(number)); } }

Node.js приложение запустить на хостинге

Всем привет! У меня проблемка. Перерыл google и satackoverflow но не могу найти решения. Написал сайт на Node+react+mongo. Соответственно все делал на локале (Запуск сервера и коддинг). Теперь взял пробное место на хостинге Timeweb. Залил туда проект, установил на сервере Node + все зависимости проекта. Код работает если вызываю команду node app.js, который запускает этот код
const express = require('express'); const MongoClient = require('mongodb').MongoClient; // const path = require('path'); // const logger = require('morgan'); // const multer = require('multer'); const bodyParser = require('body-parser'); const db = require('./config/db'); const app = express(); const port = 8000; app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); app.use(express.static(`${__dirname}/public`)); const dirname = __dirname; MongoClient.connect(db.url, (err, database) => { if (err) return console.log(err) require('./server/routes')(app, database, dirname); app.listen(process.env.PORT || port, () => { console.log(process.env.PORT || port) }) })
и выводит в консоль соответствующий порт 8000. Вопрос собственно в том, как мне сделать чтобы мое приложение запускалось и все рендерилось под доменом так же как я это видел на локале.
Можно хотябы ссылку на какуюто информаию или туториал.
Извините а такой банальный вопрос. Всем спасибо заранее!)


Ответ

Зависит от того, что у вас там за сервер. Для nginx делать так:
Для начала сам nginx установить sudo apt-get -y install nginx Открыть конфиг файл sudo nano /etc/nginx/sites-available/default и написать там:
server { listen 80; server_name имя_вашего_домена;
location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; } } Перезапустить nginx sudo service nginx restart Остаётся только в настройках DNS вашего домена направить его на ip этого сервера.

Как использовать новые геттер и сеттер?

Помогите пожалуйста отрефакторить код. Я написал компонент, который представляет из себя форму для отправки вопросов. Так же он выводит заданные на настоящий момент вопросы (пока в консоль, но это не принципиально). Вместо базы данных для учебных целей использую localstorage.
Итак, вот мой сервис, которые работает с "базой данных":
@Injectable() export class QuestionsService {
private questions: Question[];
constructor() { this.questions = localStorage.questions ? JSON.parse(localStorage.questions) : []; }
getQuestions() { console.log('qqq'); return this.questions; };
setQuestions(question): void { this.questions.push(question); localStorage.questions = JSON.stringify(this.questions); };
}
Вот описанный тип:
export class Question { text: string; speakerId: number; dateHuman: string; dateUnix: string; }
Вот компонент:
export class QuestionComponent implements OnInit {
private questions: Question[] = [];
constructor(private questionsService: QuestionsService) { }
ngOnInit() { this.getQuestions(); console.log(this.questions); }
private sendQuestion(): void { this.questionsService.setQuestions({ "text": "42256yregd", "speakerId": 23, "dateHuman": "223 oct", "dateUnix": "22222" }); };
private getQuestions(): void { this.questionsService.getQuestions().map(question => { this.questions.push(question); }); };
}
Эта система работает. Но мне хотелось бы использовать новые модные геттеры и сеттеры из стандарта es6. Вот моя попытка:
Сервис:
private questions: Question[];
constructor() { this.questions = localStorage.questions ? JSON.parse(localStorage.questions) : []; }
get questions() { console.log('qqq'); return this.questions; };
set questions(question): void { this.questions.push(question); localStorage.questions = JSON.stringify(this.questions); };
компонент:
.... ..
private sendQuestion(): void { this.questionsService.questions = { "text": "42256yregd", "speakerId": 23, "dateHuman": "223 oct", "dateUnix": "22222" }; };
private getQuestions(): void { this.questionsService.questions().map(question => { this.questions.push(question); }); };
.... ....
Но консоль выводит ошибку:
Duplicate identifier 'questions'.


Ответ

Проблема у вас вот в чем:
private questions: Question[]; // раз
get questions() { // два set questions(question): void {
У вас объявлено два свойства с одним именем. Так нельзя делать, о чем вам и говорит tsc. Эта проблема решается добавлением префикса к приватному свойству:
private _questions: Question[];
get questions() { set questions(question): void {

typedef и пользовательский тип [дубликат]

На данный вопрос уже ответили: Зачем нужен typedef? 2 ответа В чем разница между typedef struct/class и пользовательским типом, созданным с помощью struct/class? Да, я понимаю, что typedef не создаёт новый тип, а делает всего лишь дополнительное имя для данного типа, но все таки, неужели создание типа так невыгодно? typedef:
typedef struct { int size; int * massive; } MyStr;
Тип:
struct MyStr{ int size; int * massive; };


Ответ

В Си++ разницы особой нет, разница есть в чистом Си. И в Си++ это используется, скорее, как пережиток Си. В языке Си есть 4 типа пространств имен: 1) Метки (используется в конструкциях goto) 2) Тэги (имена структур, объединений и перечислений) 3) Члены структур и объединений 4) Все остальное (имена функций, объектов, констант и все typedefы).
Так же стандарт Си требует (C11 6.2.3) раздельное пространство имен для каждой из этих категорий. Ну и все компиляторы и IDE в целом поддерживают этот стандарт. То есть, все эти элементы создаются в разных пространствах имен. Поэтому, например, такой код
struct myStruct {}; myStruct str;
не скомпилируется компилятором Си (но скомпилируется Си++), потому что тип myStruct находится в раздельном пространстве имен (не в том, в котором создается переменная str). Что бы такой код работал, str нужно объявлять так:
struct myStruct str;
Что бы не писать слово struct перед каждым объявлением переменной можно использовать прием с typedef. Т.к. все, что объявлено через typedef помещается в более общее пространство имен (в то же, где и все остальные объекты), то теперь нет необходимости писать слово struct перед каждым объявлением.