Ярлыки

.htaccess (4) тестирование (8) шаблоны проектирования (3) css (5) Debian (6) docker (2) Doctrine2 (6) Git (6) html (4) java (6) javascript (13) jquery (11) LFS (3) linux (23) mac os (4) mod_rewrite (2) MSSQL (4) MySQL (18) ORM Doctrine (17) patterns (3) PDO (3) perl (7) PHP (64) PHPUnit (8) Python (15) SEO (2) Silex (1) SimpleXML (1) SQL (14) ssh (4) Ubuntu (24) Yii1 (1) Zend Framework (19) ZendFramework2 (8)

вторник, 12 апреля 2011 г.

MySQL. Настройка производительности INNODB.

8G оперативной памяти

# Очень важно для таблиц MyISAM
# 30-40% от доступной памяти
key_buffer_size = 3072M

# Очень важный параметр для INNODB
# 70-80% доступной оперативной памяти
innodb_buffer_pool_size = 5120M

# Очень важно при больших нагрузках
# рекомендуется 64M-512M, но можно увеличить
# При изменении этого параметра надо остановить сервер MySQL
# удалить файлы лога INNODB (для ubuntu /var/lib/mysql/ib_logfile*) от root
# запустить сервер
innodb_log_file_size = 512M

innodb_log_buffer_size = 16MB

# Если отключаем, то возникает опасность потери данных
# но вырастает производительность
# при 1 каждая транзакция пишется в лог (рекомендуется)
# при 2 потеря данных возможна только при полном коллапсе операционной системы
# Крайне не рекомендую отключать при загрузке больших дампов
innodb_flush_log_at_trx_commit = 0

понедельник, 11 апреля 2011 г.

PHP. Работа с соединением (посылаем ответ и продолжаем выполнение).

Если надо, например, показать страницу, закрыть соединение после запроса пользователя и продолжить выполнение длительного процесса на сервере, то можно использовать такой код ...
ignore_user_abort(true); // скрипт продолжит выполнение
                         // даже если пользователь нажмет стоп в браузере
// начинаем буфферизацию вывода
ob_start();
echo "Ваш запрос принят ...";

// размер ответа
$size = ob_get_length();

// посылаем заголовки браузеру, что соединение закрыто
header("Content-Length: $size");
header("Content-Encoding: none"); // если включен zlib, 
                                  //не отдает контент пока не закончится вывод
header("Connection: close");

// вывод
ob_end_flush();
ob_flush();
flush();

// закрываем текущую сессию, если запущена
if (session_id()) session_write_close();

/******** процесс начинает свое выполнение ********/

sleep(50);
...

PHP. Определяем, существует ли процесс php-скрипта (unix).

Тестировалось на unbuntu.
Файл лежит в каталоге веб-сервера, выставлены права на исполнение.

Скрипт

#!/usr/bin/php
<?php

...
if(processExists()) {
    die('Уже запущен');
}
...

// скрипт исполняется значительное время

Функция

function processExists($file = false) {
    if(!$file) $file = basename (__FILE__);

    exec("ps -C $file -o pid=", $pids);
    
    return count($pids) > 1 ? true : false;
}

PHP. realpath доступ к каталогам верхнего уровня.

// На два каталога выше
$path = realpath(dirname(__FILE__) . '/../..');

MySQL. Архивирование дампа.

Для bz2 - bunzip2
mysqldump < mysqldump options> | gzip > outputfile.sql.gz
gunzip -v outputfile.sql.gz
gunzip < outputfile.sql.gz | mysql -udbuser -pdbpwd dbname

// Дамп выборки (разделение - символ табуляции)
mysql -e "SET NAMES 'utf8'; SELECT * FROM mytable" -umyuser -pmypwd mydb > mydump.txt

// Только данные (INSERT), одна строка
mysqldump -uDBUSER -pDBPWD DBNAME TABLENAME --skip-triggers --compact --no-create-info --where='id LIMIT 1' > mydump.sql

воскресенье, 10 апреля 2011 г.

PHP. Аналог mysql_real_escape_string для расширения mssql.

function mssql_escape($data) {
    if(is_numeric($data))
        return $data;
    $unpacked = unpack('H*hex', $data);
    return '0x' . $unpacked['hex'];
}

SQL. MySQL Выборка дубликатов.

// Doctrine
$emails = Doctrine_Query::create()->select('email')->from('User')
            ->groupBy('email')->having('COUNT(email) > 1')
            ->setHydrationMode(Doctrine::HYDRATE_ARRAY)->execute()

// SQL
SELECT email FROM user GROUP BY email HAVING COUNT(email) > 1

пятница, 8 апреля 2011 г.

Transact-SQL. Преобразование типа поля при выборке.

Используем команды CAST и CONVERT

Подробно - http://msdn.microsoft.com/ru-ru/library/aa226054%28v=sql.80%29.aspx

Допустим есть поле типа uniqueidentifier. При выборке средствами php (mssql_connect ...) получим мусор, а нам нужна строка.

Транслируем новый тип поля в запросе
SELECT... CAST(F_CITIZENSHIP AS VARCHAR(255)) AS CITIZENSHIP ... FROM ...
и получаем на выходе строку.

C#. Работа с датой и временем.

// Сегодня 0 часов
DateTime today = DateTime.Today;

// 8.04.2011 14:30:0
DateTime myDate = DateTime(2011, 4, 8, 14, 30, 0);

// Через 2 дня 8 часов и 20 минут
DateTime newDate = myDate.AddDays(2).AddHours(8).AddMinutes(20); 

// Месяц назад
DateTime myDate = today.AddDays(-30);

// Строка
String strMyDate = myDate.Date.ToString();


//В Transact-SQL - на 30 дней раньше текущей даты
... WHERE my_date < GETDATE() - 30 ...

среда, 6 апреля 2011 г.

C#. Блокировка важной части кода (lock).

// using System.Threading;

    class Account
    {
        private Object thisLock = new Object();
        int balance;

        Random r = new Random();

        public Account(int initial)
        {
            balance = initial;
        }

        int Withdraw(int amount)
        {
            // Состояние никогда не будет true пока работает lock
            if (balance < 0)
            {
                throw new Exception("Negative Balance");
            }

            // Закомментируем следующую строку и смотрим что будет
            lock (thisLock)
            {
                if (balance >= amount)
                {
                    Console.WriteLine("Balance before Withdrawal :  " + balance);
                    Console.WriteLine("Amount to Withdraw        : -" + amount);
                    balance = balance - amount;
                    Console.WriteLine("Balance after Withdrawal  :  " + balance);
                    return amount;
                }
                else
                {
                    return 0; // транзакция отклонена
                }
            }
        }

        public void DoTransactions()
        {
            for (int i = 0; i < 100; i++)
            {
                Withdraw(r.Next(1, 100));
            }
        }
    }

    class Test
    {
        static void Main()
        {
            Thread[] threads = new Thread[10];
            Account acc = new Account(1000);
            for (int i = 0; i < 10; i++)
            {
                Thread t = new Thread(new ThreadStart(acc.DoTransactions));
                threads[i] = t;
            }
            for (int i = 0; i < 10; i++)
            {
                threads[i].Start();
            }
        }
    }

вторник, 5 апреля 2011 г.

OSX. Установка PHP с поддержкой mssql в Leopard.

Недавно решился обновиться до Leopard, до этого сидел на Tiger. Мак у меня довольно старый - powerbook g4 1.5GHz 1G RAM.

Ставил MAMP, но там с расширениями все скучно. Поэтому ставлю macports и php5 из портов ...

PHP. Подключение к MSSQL (удаленно).

Так случилось что невозможно установить постоянный порт для удаленного MSSQL сервера. Почему - это длинная и скучная история. Порт назначается динамически при старте сервера бд.

Есть админ доступ на сервер через удаленный рабочий стол Windows.

Как настроить SQL Server 2005 для удаленных подключений - читаем тут
http://support.microsoft.com/kb/914277

Вкратце:

a. Разрешите удаленные подключения к SQL Server 2005
  • 1. Нажмите кнопку Пуск, выберите Программы, Microsoft SQL Server 2005, перейдите к пункту Средства настройки, затем выберите Настройка контактной зоны SQL Server.
  • 2. На странице Настройка контактной зоны SQL Server 2005 выберите Настройка контактной зоны для служб и соединений.
  • 3. На странице Настройка контактной зоны для служб и соединений разверните Database Engine, выберите Удаленные соединения, затем Локальные и удаленные соединения, выберите нужный протокол для вашей сетевой среды и нажмите кнопку Применить. Примечание. Нажмите кнопку OK при появлении следующего сообщения Изменения в настройках соединений вступят в силу только после перезапуска службы компонента Database Engine.
  • 4. На странице Настройка контактной зоны для служб и соединений разверните Database Engine, выберите Службы, нажмите кнопку Стоп, дождитесь остановки службы MSSQLSERVER, затем нажмите кнопку Пуск для повторного запуска службы MSSQLSERVER.

b. Включите службу SQL Server Browser

Об обозревателе подробно читаем тут - http://msdn.microsoft.com/ru-ru/library/ms165724%28v=sql.90%29.aspx

  • 1. Нажмите кнопку Пуск, выберите Программы, Microsoft SQL Server 2005, перейдите к пункту Средства настройки, затем выберите Настройка контактной зоны SQL Server.
  • 2. На странице Настройка контактной зоны SQL Server 2005 выберите Настройка контактной зоны для служб и соединений.
  • 3. На странице Настройка контактной зоны для служб и соединений выберите SQL Server Browser, выберите Авто для Тип запуска, затем нажмите кнопку Применить. Примечание. При выборе параметра Авто служба SQL Server Browser запускается автоматически при каждом запуске Microsoft Windows.
  • 4. Нажмите кнопку Пуск, затем нажмите кнопку OK.

c. Создание исключений в брандмауэре Windows

SQL Server 2005 использует идентификатор экземпляра в качестве части пути установки файлов программы. Для создания исключения для всех экземпляров SQL Server необходимо определить верные идентификаторы экземпляров. Для получения идентификатора экземпляра выполните следующие действия.

  • 1. Нажмите кнопку Пуск, выберите Программы, Microsoft SQL Server 2005, перейдите к пункту Средства настройки, затем выберите Диспетчер конфигурации SQL Server.
  • 2. На правой панели диспетчера конфигурации SQL Server щелкните службу средства просмотра SQL Server, в главном окне правой кнопкой мыши щелкните название экземпляра, затем щелкните Свойства.
  • 3. На странице SQL Server Browser Properties (Свойства SQL Server Browser) щелкните вкладку Дополнительно, в списке свойств выберите идентификатор экземпляра, затем нажмите кнопку OK.

Для открытия брандмауэра Windows выберите в меню Пуск пункт Выполнить, введите команду firewall.cpl и нажмите кнопку ОК.

Создание исключения для SQL Server 2005 в брандмауэре Windows

Для создания исключения для SQL Server 2005 в брандмауэре Windows выполните следующие действия.

  • 1. В брандмауэре Windows щелкните вкладку Исключения, затем щелкните Добавить программу.
  • 2. В окне добавления программы нажмите кнопку Обзор.
  • 3. Щелкните исполняемую программу C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn\sqlservr.exe, щелкните Открыть, затем нажмите кнопку OK.

Примечание. В зависимости от места установки SQL Server 2005 путь может отличаться. MSSQL.1 — это идентификатор экземпляра, полученный на этапе 3 предыдущей процедуры.

Создание исключения для службы SQL Server Browser в брандмауэре Windows

Для создания исключения для службы SQL Server Browser в брандмауэре Windows выполните следующие действия.

  • 1. В брандмауэре Windows щелкните вкладку Исключения, затем щелкните Добавить программу.
  • 2. В окне добавления программы нажмите кнопку Обзор.
  • 3. Щелкните исполняемую программу C:\Program Files\Microsoft SQL Server\90\Shared\sqlbrowser.exe, щелкните Открыть, затем нажмите кнопку OK.

Примечание. В зависимости от места установки SQL Server 2005 путь может отличаться.

Лезем на сервер и смотрим имя экземпляра сервера бд, к которому требуется удаленное подключение.
Делаем это в SQL Server Cofiguration Manager.
Смотрим список служб - SQL Server (MSSQLSERVER). В моем случае это MSSQLSERVER.

Далее с нашей машины пытаемся подключиться к серверу при помощи sqlcmd (утилиты для работы с сервером из командной строки, аналог mysql). Подробно читаем тут - http://msdn.microsoft.com/ru-ru/library/ms165724%28v=sql.90%29.aspx или вызываем sqlcmd /? для справки.
sqlcmd -S tcp:xx.x.xx.xxx\MSSQLSERVER

В ответ:
Login failed for user ''. The user is not associated with a trusted SQL Server connection.

Оно и понятно - доступ закрыт. На сервере используется авторизация Windows (учетные записи ос).
Мы хотим авторизацию сервера бд. Придется создать пользователя и добавить его к конкретной базе.
А также задать ему роль (у меня db_datareader, читатель).

1. Создание имени входа SQL Server с использованием проверки подлинности SQL Server (среда SQL Server Management Studio)

Подробно - http://msdn.microsoft.com/ru-ru/library/aa337562%28v=SQL.90%29.aspx

2. Создание пользователя базы данных в среде SQL Server Management Studio

Подробно - http://msdn.microsoft.com/ru-ru/library/aa337545%28v=SQL.105%29.aspx

Ну и задаем ему необходимые права в свойствах.

Теперь когда у нас открыт доступ на сервере и есть учетная запись, можно пробовать подключиться с sqlcmd:

sqlcmd -S tcp:xx.x.xx.xxx\MSSQLSERVER -U my_user -P my_pwd
1> SELECT name FROM sys.databases
2> GO
name

---------------------------------
my_db

Мы на сервере. Все ок.

Теперь для php-скрипт из пред поста меняем данные подключения:

$serverName = "xx.x.xx.xxx\MSSQLSERVER";
$connectionInfo = array (
    'Database' => 'my_db',
    'UID'  => 'my_user',
    'PWD'  => 'my_pwd'
);

PHP. Подключение к MSSQL (локально).

Установлен MSSQL Server 2005 на Windows 7 Professional ...

Смотрим список процессов:
C:\Users\leon>tasklist
Имя образа                     PID Имя сессии          № сеанса       Память
========================= ======== ================ =========== ============
...
sqlservr.exe                  2408 Services                   0 1 505 316 КБ
...

C:\Users\leon>netstat -ano
 Имя    Локальный адрес        Внешний адрес          Состояние       PID
...
TCP    127.0.0.1:1434         0.0.0.0:0              LISTENING       2408
...

Таким образом убеждаемся, что сервер запущен и слушает порт 1434

Проверяем разрешен ли TCP/IP для SQL-сервера:

SQL Server Configuration Manager -> Network Configuration -> Protocols -> TCP/IP enabled

Документация драйвера MSSQL для PHP от Microsoft тут - http://msdn.microsoft.com/ru-ru/library/ee229547%28v=SQL.10%29.aspx

Качаю и ставлю драйвер MSSQL для PHP тут -
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=ccdf728b-1ea0-48a8-a84a-5052214caad9

Системные требования для установки драйвера - http://msdn.microsoft.com/ru-ru/library/cc296170%28v=SQL.90%29.aspx

Для PHP 5.3.x в php.ini добавляю следующее (dll положил в ext):

...
[PHP_SQLSRV]
extension=php_sqlsrv_53_nts_vc9.dll
...

Далее пытаюсь подключиться (подробности http://msdn.microsoft.com/ru-ru/library/cc296161%28v=sql.90%29.aspx):

/*
Connect to the local server using Windows Authentication and specify
the AdventureWorks database as the database in use. To connect using
SQL Server Authentication, set values for the "UID" and "PWD"
 attributes in the $connectionInfo parameter. For example:
$connectionInfo = array("UID" => $uid, "PWD" => $pwd)); 
*/
$serverName = "(local)";
$connectionInfo = array("Database" => "MyMSDb");
$conn = sqlsrv_connect($serverName, $connectionInfo);

if( $conn )
{
     echo "Connection established.\n";
}
else
{
     echo "Connection could not be established.\n";
     die(print_r( sqlsrv_errors(), true));
}

//-----------------------------------------------
// Perform operations with connection.
//-----------------------------------------------

/* Close the connection. */
sqlsrv_close($conn);

Получаю ошибку:

The SQL Server Driver for PHP requires the SQL Server 2008 Native Client ODBC Driver (SP1 or later) to communicate with SQL Server. That ODBC Driver is not currently installed. Access the following URL to download the SQL Server 2008 Native Client ODBC driver for x86: http://go.microsoft.com/fwlink/?LinkId=163712

Клиент стоял для MSSQL Server 2005, значит качаем и ставим для 2008
http://download.microsoft.com/download/0/E/6/0E67502A-22B4-4C47-92D3-0D223F117190/sqlncli.msi

Запускаю скрипт - ошибка:
...
[Microsoft][SQL Server Native Client 10.0][SQL Server]Login failed for user 'leon-PC\leon'
...
Клиент работает - это хорошо, авторизация не проходит ...
Вместо MyMSDb ставим имя реальной базы данных и на локальной машине подключение проходит.

Connection established.

понедельник, 4 апреля 2011 г.

C#. Visual Studio 2008 отладка dll.

Создаем проект типа Class Library (библиотека), который компилируется в dll и используется в клиентском коде.

Пример:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyClassLib
{
    public class MyClass
    {
        public int DoIt(int a, int b)
        {
            return a + b;
        }
    }
}

Вызываем Immediate Window: Alt + Ctrl + I и набираем:
MyClassLib.MyClass obj = new MyClassLib.MyClass();
obj.DoIt(10, 15);
25

Таким образом можем добавить точки останова.

Transact-SQL. Примеры.

Переменные


USE TestDatabase
-- Объявление переменных
DECLARE @EmpID INT, @EmpName VARCHAR(40)
-- Задание значения переменной @EmpID
SET @EmpID = 1
-- Задание значения переменной @EmpName
SELECT @EmpName = UserName FROM Users WHERE UserID = @EmpID
-- Вывод переменной @EmpName в результат запроса
SELECT @EmpName AS [Employee Name]
GO

-- Примечание. В этом примере используется группировка слов в переменную — конструкция [Employee Name] 
-- воспринимается как одна переменная, так как слова заключены в квадратные скобки


Системные функции


USE TestDatabase
-- Использование агрегативной функции для подсчета средней зарплаты
SELECT AVG(BaseSalary) AS [Average salary] FROM Positions
GO
-- Использование скалярной функции для получения имени базы данных
SELECT DB_NAME() AS [DATABASE name]
GO
-- Использование скалярной функции для получения имени текущего пользователя
DECLARE @MyUser CHAR(30)
SET @MyUser = USER_NAME()
SELECT 'The current user''s database username is: '+ @MyUser
GO
-- Использование функции-указателя для получения данных с другого сервера
SELECT * FROM OPENQUERY(OracleSvr, 'SELECT name, id FROM owner.titles')
GO


Выражения


USE TestDatabase
-- Использование DDL
CREATE TABLE TempUsers (UserID INT, UserName NVARCHAR(40), DepartmentID INT)
GO
-- Использование DCL
GRANT SELECT ON Users TO PUBLIC
GO
-- Использование DML
SELECT UserID, UserName + ' ' + UserSurname AS [USER FULL Name] FROM Users
GO
-- Использование DDL
DROP TABLE TempUsers
GO


Динамическое конструирование выражений

USE master
-- Задание динамических данных
DECLARE @dbname varchar(30), @tablename varchar(30)
SET @dbname = 'TestDatabase'
SET @tablename = 'Positions'
SET @column = 'BaseSalary'
-- Использование динамических данных
EXECUTE ('USE ' + @dbname + ' SELECT AVG(' + @column + ')
  AS [Average salary] FROM @tablename ' + @tablename)
GO

Выборка


В строке сравнения разрешается использовать подстановочные символы:
% - любое количество символов;
_ - один символ;
[] – любой символ, указанный в скобках;
[^] – любой символ, не указанный в скобках.
-- Выбрать все записи из таблицы Users, у кого в имени вторая буква не V
SELECT * FROM Users WHERE UserName LIKE '_[^v]%'

-- Выбрать записи колонок UserName и UserSurname из таблицы Users, у кого 
-- PositionID между 2 и 3, результирующую колонку назвать Full name.
SELECT [UserName] + ' ' + [UserSurname] AS 'Full name' FROM Users
  WHERE PositionID BETWEEN 2 AND 3

-- Сосчитать суммарную зарплату отдела с идентификатором 1
DECLARE @DepID int
SET @DepID = 1
SELECT DepartmentName AS 'Department name',
    (SELECT SUM(Positions.BaseSalary) FROM Positions
       INNER JOIN Users ON Users.PositionID = Positions.PositionID
       WHERE Users.DepartmentID = @DepID
    ) AS 'Summary salary'
  FROM Departments
  WHERE DepartmentID = @DepID

Аналог LIMIT в MySQL

SELECT TOP 10 * FROM MY_TABLE
-- аналогично
SELECT * FROM MY_TABLE LIMIT 10